ひとりぶろぐ

価値ある情報をユーザー視点で発信するブログ

iOSのWebViewに拡張メニューを追加するWebViewExMenu

      2016/03/24

MobileSafariとWebView全般に拡張メニューを追加するWebViewExMenuというTweakを作ってみました。

MobileSafariの拡張じゃありません。Webブラウザの拡張でもありません。WebView全般で有効。

WebViewというのは、iPhoneのアプリケーションの中全般で部品として使われています。

Evernoteの中でも、Twitterクライアントの中でも、RSSリーダーの中でも、2ちゃんねるリーダーの中でも、サードパーティ製のWebブラウザでも有効です。

例えば、どこからでもはてなブックマーク登録Bookmarkletを呼び出したり、といったことができます。(自分はTwitterクライアント内のブラウザからはてブするために作りました)

スクリーンキャスト 1 どこでもはてブ

どこでもはてブできます。

スクリーンキャスト 2

実際の動作の様子です。
MobileSafariのみならず、RSSリーダーからも呼び出せています。

場所を選ばずメニューの表示ができ、機能の実行ができていることが分かるかと思います。

WebViewExMenuの表示方法

WebViewExMenuは、MobileSafari、WebView上でトリプルタップをすると表示されます。

webviewexmenu01.png

ただ、ページ中がタップ可能なもので占められている場合など、タップを避けつつメニューを表示することが困難なケースはあるかと思います。

汎用性の実現、片手操作が可能であること、実装の簡単さからトリプルタップを選択しました。(続きは[MORE]から)

 

WebViewExMenuの持つ機能

機能は三つあります。

  • Bookmarklet(JavaScript)実行と、実行結果のクリップボードへの転送
  • テキストエンコーディング選択
  • ソース表示モード移行

Bookmarklets(JavaScript)実行と、実行結果のクリップボードへの転送機能について

MobileSafariのブックマークのルートにあるBookmarkletsフォルダ(Bookmarkletの複数形でBookmarklets)にあるブックマークレットを一覧から選んで実行できます。

webviewexmenu02.png webviewexmenu03.png

Bookmarkletsフォルダの下層は再帰走査しません。ベタで置いてください。

SafariのブックマークからBookmarkletを実行する場合との違いは、実行結果に何らかの文字列が含まれていたら、それをクリップボードに転送することです。

例えば、以下のBookmarkletを実行すると、表示中のページのタイトルとURLがクリップボードに転送されます。

javascript:document.title + ‘ ‘ + window.location

XPathで掘れば、大概のスクレイピングはできるかと思います。
ページから欲しい情報を抜いてきて、サクっとクリップボードにコピー、ということができるわけです。

副次的なメリットとして、ブックマークレット実行までに、テキスト選択が解除されてしまうことがないというものがあります。

よって、選択テキストを取得して処理するタイプのBookmarkletを素直に動かすことができます

webviewexmenu04.png

Safariから選択テキストを扱うBookmarkletを実行する場合、ブックマークボタンを押した時点でテキストの選択が解除されてしまうため、少々面倒なBookmarkletの作りと手順が必要なのです。

iPhoneのwindow.getSelection()について – YutaKikuchiのTechBlog iPhoneのwindow.getSelection()について - YutaKikuchiのTechBlog

以下の例では、選択中のテキストをダブルクォートで括ったものがBookmarkletの返り値となり、クリップボードにコピーされます。

javascript:'”‘+document.getSelection()+'”‘

冒頭の「javascript:」は必要ありませんが、Safariのブックマークから起動する場合のことを考えて、付けておくのがいいでしょう。

逆に、クリップボードにコピーされたくない場合は、Bookmarkletの最後を文字列を返さないメソッドで終わるか、void(0)かなんかを実行してください。

Bookmarklets(JavaScript)実行機能の制約

Twitterクライアントなどの所有するURL Schemeから始まるURLをwindow.locationにセットして、別のアプリケーションを呼び出すBookmarkletは、iPhoneでは多用されます。

しかし、こうしたタイプのJavaScriptは、必ずしも期待通りの結果をもたらすとは限りません。JavaScriptを動かしたアプリケーション内のWebViewのdelegateメソッドの実装次第です。

UIWebViewの内部リンクからSafariを開いてみよう! – u_ UIWebViewの内部リンクからSafariを開いてみよう! - u_

例えば、Tweetlogixの中のWebViewでURL Scheme経由で別アプリケーションを呼び出そうとしても無反応

一方で、Tweetingsだと呼び出せるといったような感じです。

JavaScript / Bookmarkletのデバッグ

JavaScript / Bookmarkletを実行しても、ウンともスンとも言わない。

そんなときはどうしましょう?

「設定>Safari>デベロッパ>デバッグコンソール」をオンにしましょう。エラーが出ていれば、それをデバッグコンソールで教えてくれるようになります。

デバッグコンソールは、Safariのアドレスバーの下に表示されます。

テキストエンコーディング選択機能について

MobileSafari、WebViewでちょっと昔めのページを訪れると、ときどき化けて見られないことがあります

webviewexmenu05.png

ページの実際のエンコーディングと、ページ内で指定されているcharsetに不一致があったり、正しくない書き方だったりするのでしょう。

こんなとき、MobileSafari / WebViewだと処置のしようがありません。処置のしようがないんです。

さて、そんなWebページの文字化けの対策になるのがテキストエンコーディング選択機能です。

  • デフォルト
  • Shift JIS
  • ISO 2022-JP
  • EUC-JP
  • Shift JIS X0213
  • UTF-8

上記の六つのテキストエンコーディングから任意に選んで適用することができます。

そのどれかを選択すれば日本語の文字化けは回避することができるかと思います。

webviewexmenu06.png webviewexmenu07.png

選択できるテキストエンコーディングは無数にあり、それを選択できるようにすることは可能ですが、無数の中から残したいものを選ぶUIを作る必要があるので、とりあえずはこのようにしてみました。


ソース表示モードについて

WebViewExMenuの項目「ソースを表示」を選択すると、表示中のページのhtmlのソースを見ることができます

webviewexmenu08.png

シンタックスハイライティングされ、行番号まであって見やすい表示です。

webviewexmenu09.png

ソース表示モード中にWebViewExMenuを起動すると、「ソースを表示」から「ソース表示を解除」とボタン名が変わっています。

「ソース表示を解除」ボタンを押すと、通常のモードに戻ります。

設定

WebViewExMenuをインストールすると、「設定>WebViewExMenu」が現れます。

webviewexmenu11.png webviewexmenu12.png
  • Top Level JS Menu:
    • メインメニューとJavaScript実行メニューの階層を入れ替え、JavaScript実行メニューを最上層に持っていきます。JavaScriptの実行がクイックにできるようになります。Bookmarkletこそ至上! と考える人はオンにしてください。メインメニューへは、Bookmarkletメニューの後ろの「メインメニュー」という項目から移行できます

※「PlainText.app First」の設定項目はVer.0.4から削除されています。

webviewexmenu13.png

既知の不具合

  • WebViewを使うアプリケーションが起動不能になるケースがある模様
  • Bookmarkletを編集してもすぐには反映されません。WebViewの初期化時にBookmarkletを読み込んでいるので、一度WebViewを閉じないと更新は反映されません。都度読み込もうとすると不具合が起きるための仕様
  • URL Schemeで他のアプリケーションを呼び出そうとしても、うまくいかないことがある。「Bookmarklets(JavaScript)実行機能の制約」を読んでください

既にBookmarkletsフォルダはあるのですが、JavaScript実行メニューに表示されません。バグですか?

WebViewの初期化時にBookmarkletを読み込んでいます。

初期化とは、例えばMobileSafariなら、新しくウインドウを作ることが初期化です。

ここでWebViewExMenuのJavaScript実行メニューの内容が読み込まれます。

初期化時に読み込んだBookmarkletは、そのWebViewが保持します。

MobileSafariのBookmarkletsフォルダに手を加え、さらにMobileSafariで新しくウインドウを作った場合、古いウインドウと新しいウインドウのJavaScript実行メニューの内容は違ったものになります。

MobileSafariにBookmarkletsフォルダを作ったのが、WebViewExMenuを実行しようとしているWebViewが生成されたのより後である場合、まだそれらが無かったときにそのWebViewは生成されているため、MobileSafariにBookmarkletsフォルダの中身は表示されません。

MobileSafariなら、新しくウインドウを作ってからWebViewExMenuを実行してください。

この辺は感覚的でないのは分かりますが、都度読み込もうとすると不具合が出るため、このような仕様になっています。

Bookmarkletを編集してもすぐには反映されないのですが、バグですか?

Bookmarkletを編集してもすぐには反映されません。

WebViewの初期化時にBookmarkletを読み込んでいるので、一度WebViewを閉じないと更新は反映されません。都度読み込もうとすると不具合が起きるための仕様です。

想定質問: メニューの表示方法を〜

片手でできる範囲の起動方法ではベストだと思っているので、考えを曲げる気はありません。

想定質問: Activator / SBSettings / ActionMenuには〜

Activator、SBSettingsの場合は1対多の通信となり、「どのWebViewで実行するか」を絞る手順が必要になります。

それを解決する手段はありませんし、そんなことをしたい人もまた居ないはずです。1画面に複数のWebViewが存在する、ということもあります。

ActionMenuならいけますが、メニューの奥まったところから実行するのは得策ではないと思います。コピー/ペーストに並べて置くようなものでもありません。

よって、対応するつもりはありません。

履歴

  • 0.4-1 2011.07.18 0.3が不安定だったため、webviewexmenudというDaemonにSpringBoardの代わりをさせるように。PlainText.app連携機能を削除
  • 0.3-1 2011.06.09 PlainText.app連携機能を改修。拡張子txtもWebViewExMenuのJavaScript実行メニューに追加するようにした。iOS4.3.3で動作がおかしかったので、もしかしたら直るかも?という修正
  • 0.2-1 2011.06.04 PlainText.app連携機能搭載。メニュー階層の入れ替え機能搭載。設定項目新設
  • 0.1-1 2011.06.02 初版

動作確認環境

  • iOS 4.3.3 (iPad未テスト)
  • iOS 4.2.1 (iPad未テスト)

インストール

New野良リポジトリに置いておきました。

「WebViewExMenu」で検索してください。

無保証です。

謝辞

WebViewExMenuのJavaScript実行機能は、fladdictさんの「SpellBook

fladdict » SpellBook 右クリックからブックマークレットを起動できる拡張 fladdict » SpellBook 右クリックからブックマークレットを起動できる拡張

paella (@hkato193)さんの「LibraMagico

[Mac][SIMBL][Bookmarklet] SafariでもSpellBookの感動が得られるプラグイン「LibraMagico」を書いてみた – Ni chicha, ni limona -平均から抜けられない僕-

にインスパイアされて作りました。アイデアは随分前から考えていたんですけどね。

 - iPhone, Jailbreak