UIWebViewはデフォルトで、リンクを長押ししてるとActionSheetが出てきます。選択肢がOpenとCopyしかないので、実質あまり意味がなかったりしますが。
なのでこのActionSheetのボタンをアプリでカスタマイズしたい諸兄も多いことでしょう。
そんなときのTips。
UIWebViewはデフォルトで、リンクを長押ししてるとActionSheetが出てきます。選択肢がOpenとCopyしかないので、実質あまり意味がなかったりしますが。
なのでこのActionSheetのボタンをアプリでカスタマイズしたい諸兄も多いことでしょう。
そんなときのTips。
UIWebViewではページの読込ませ方によってcanGoBack, canGoForwardの挙動が変わるようです。
これはcanGoBackだけでなく、実際にgoBackしても動作しなくなります。historyがきちんと更新されるのはloadRequest:だけのようです。
Javascriptでhistoryがいじれるといいのですが、試しにやってみたところ期待通りにはいきませんでした。できそうなものなんですけどね、、
相変わらずUIWebViewと格闘中です。
AppStoreにあるブラウザアプリで、フォントサイズが変更できるものがあったので、真似してみることに。
やり方は簡単、次のようにやるだけ。
script = @"document.getElementsByTagName('body')[0].style.webkitTextSizeAdjust='120%';";
[webView stringByEvaluatingJavaScriptFromString:script];
jQueryなどでスタイルのfont-sizeをいじっても、HTML上のスタイル定義のされ方によって適用されたりされなかったり安定しません。webkitTextSizeAdjustを使えばそういうときでもイチコロです。
元ネタはこちら。
http://stackoverflow.com/questions/589177/how-to-increase-font-size-in-uiwebview
結局解決できていません、本件。
あれからさらにいろいろ試して、見えてきたのは[NSURLRequest cachePolicy]。
そもそもは、デフォルトのNSURLCache実装がstoreCachedResponseでデータを渡されていてもcachedResponseForRequestで返すものと返さないものが存在している、というところでした。
なぜか?
データは違えども、NSCachedURLResponse、NSURLResponseの状態は概ね同じ。違うのは[NSURLRequest cachePolicy]。デフォルトのNSURLCacheはNSURLRequestReturnCacheDataElseLoad、NSURLRequestReturnCacheDataDontLoadの場合はキャッシュを返すけど、NSURLRequestUseProtocolCachePolicyの場合は返さないようです。
相変わらず理由はわかりませんが、真似してみることに。
ふむ、落ちなくなった。
前回も落ちなくなった後、他の箇所をいじっていたら再発したので安心できませんが、とりあえず改善。どうやらものすごく微妙なバランスで動いているようです、NSURLCache。
ただ、割といろんなリソースがNSURLRequestUseProtocolCachePolicyでリクエストされているので、NSURLRequestUseProtocolCachePolicyだとキャッシュを返しちゃだめとなるとローカル保存からWebページを再現するのは難しいのかもしれません。。
原因が特定できなくて困っていた、Googleのトップページでだけ発生する落ちバグがあったわけですが、なんとなく原因が特定できたくさい。
ちなみにこれは次のような現象。
あちこちのサイトをキャッシュしてみても、上記現象が起きるのはなぜかGoogleだけ。Googleとは言っても、ニュース(http://news.google.co.jp/)では大丈夫だったりします。
さらに、EXC_BAD_ACCESSは通常過剰releaseによって解放済みのメモリにアクセスすると起きるものですが、いくらretainかましても改善しませんでした。過剰releaseならGoogle以外でも発生するだろうし、ランダム要素があるなら http://www.google.co.jp/ で100%発生するというのはおかしいので、やはりGoogleさんのサイト構造に起因するものとして調べてみました。
とはいってもソースもないライブラリの中で起きてる例外なので調べようもなく、できることといえばファイルの構成をよくよくみてみるくらい。じーっ、とよく見てみると、試してみたサイトの中で、唯一 http://www.google.co.jp/ だけHTML5のmanifestファイルが含まれていました!
試しにmanifest指定を削ってみます。
落ちない! これか!
理屈はわかりませんが、とりあえずmanifest指定を削ってしまうとよいようです。
(2/21追記)
いろいろいじってるうちにまた落ちるようになりました。違うらしい。
iPhoneを使っていて、最もイライラするのは通信状況。電波の受信感度はバッチリでも通信できないということが珍しくありません。
iPhoneのせい、というよりは、Softbankの電波のせいなわけですが。
iPhoneのSafariは(というか普通のブラウザはみな)一回みたページに戻る場合でも 最新かどうかを判断するため通信しようとするので、通信状況が不安定だとブラウジングがものすごくイライラします。
そこで一度みたページをすべてキャッシュし、キャッシュがあれば最新チェックもなにもかもすっ飛ばして表示してくれるアプリを作ろうとしています。が、これがなかなかに難儀しています。
いままでチャレンジしてみたこととしては、
(1) webView:shouldStartLoadWithRequest:navigationType: で保存すべきURLがわかるか?
(2) いっそのこと webView:shouldStartLoadWithRequest:navigationType: に飛んで来たURLからHTMLを取得し、中身をparseして画像やCSSなどのリンクをたどればできるんじゃないか?
(3) uiWebView:resource:willSendRequest:redirectResponse:fromDataSource: でなら画像やCSSも含めて呼び出されているっぽいからいけるんじゃない?
(4) NSURLCacheでどうよ?
という流れ。
結論としては、(4)でなんとかなりそう。
ただしstoreCachedResponse:forRequest: はredirectの絡みで使えないため、
という実装になりそうである。なかなか大変。
UIWebViewでサイトをみると、User-AgentがSafariと違うため、一部のサイトでは iPhoneであると認識できずにPCサイトに連れていかれてしまいます。(Yahooとか)
ちょっと前までは
- (BOOL)webView:(UIWebView *)webView
shouldStartLoadWithRequest:(NSURLRequest *)request
navigationType:(UIWebViewNavigationType)navigationType
{
NSMutableURLRequest *req = (NSMutableURLRequest*)request;
[req setValue:USER_AGENT_STRING forHTTPHeaderField:@"User_Agent"];
return YES;
}
でよかったようですが、iOS4.2でやってみると期待通りには動いてくれませんでした。 色々やってみたところ、
-(NSURLRequest*) uiWebView:(id)webView
resource:(id)identifier
willSendRequest:(NSURLRequest *)request
redirectResponse:(NSURLResponse *)redirectResponse
fromDataSource:(id)dataSource
{
NSMutableURLRequest *req = (NSMutableURLRequest*)request;
[req setValue:USER_AGENT_STRING forHTTPHeaderField:@"User-Agent"];
return req;
}
とやると期待通りになってくれるようです。
これはUIWebViewWebViewDelegateというprotocolで、WebViewDelegateと同じ内容を 備えている非公開protocolのようです。非公開なのでこれを使って審査が通るかどうかは 未知数ですが、UIWebViewWebViewDelegateを使うと色々便利なことが出来るので、 いま作ってるアプリではバリバリ使ってみてます。 審査が通るといいなぁ。
UIWebViewWebViewDelegateは非公開なので
#import <UIKit/UIKit.h>
とやっても宣言に含まれてきません。 なので@interfaceは普通に
@interface HogeViewController : UIViewController<UIWebViewDelegate>
とだけやっておいて、.m で知らん顔して実装してしまえばUIWebViewが呼び出してくれます。=D もちろんUIWebViewのdelegateにHogeViewControllerを設定するのは必要です。