- ベストアンサー
iPhoneアプリの開発について - オフライン表示の方法がわからない
- iPhoneアプリの開発において、ウェブサイトをローカルに保存しオフラインで表示する方法がわかりません。試した方法では正しく表示されず、スマートフォン向けのページがPC版として表示されました。
- 使用したプログラムに一部間違いがあるのか、それとも方法自体が間違っているのかわかりません。ご指摘いただけると幸いです。
- 他の方法として、Qiitaの記事を参考にして試しましたが、同様にオフラインでの表示ができませんでした。
- みんなの回答 (2)
- 専門家の回答
質問者が選んだベストアンサー
> iOSシミュレータでは機内モードができずずっとPCのWIFIを切って実行していたのでそれが原因だったと思います。 シミュレータなら、その方法でオフラインにできるはずです。 サンプルプロジェクトのRNCachingURLProtocol.mのuseCacheメソッド内の reachableがNOになればオフラインと認識されるわけですが、 私の方でシミュレータを使ってWi-FiをOFFにしたらreachableはNOになりました。 うまく行かないならオフラインモードとオンラインモードを切り替えるスイッチを 画面内に作り、useCacheメソッドでそのスイッチの値を返却するよう サンプルプロジェクトを改造してもよいと思います。 で、このサンプルプロジェクトがちゃんと動作しているのかもう少し調べてみました。 すると、cnn.com、bbc.comとwww.yahoo.co.jpはちゃんとキャッシュできるのですが、 yahoo.comとwww.google.co.jpは一部しかキャッシュされてなく、正しく動作して いないことがわかりました。 (www.yahoo.co.jpとwww.yahoo.co.jpは独自で追加したものです。) その原因を調べたところ、yahoo.comとwww.google.co.jpは内部でhttpsに リダイレクトされているようで、このサンプルプロジェクトがhttpsのページを キャッシュするようにできていないためでした。 問題は、このサンプルプロジェクトのRNCachingURLProtocol.mの canInitWithRequestメソッド内で[[request URL] scheme]が @"http"の場合だけYESを返すようになっているところです。 ここを@"http"または@"https"の場合とするよう条件式を変更するだけで、 httpsのページにも対応でき、yahoo.comとwww.google.co.jpも 正しくキャッシュできるようになりました。 ここを修正して、うまくオフライン表示できるか試してみてはどうでしょうか? > ここから特定のキャッシュのパスを取得するにはどうしたらいいでしょうか? > またパスを取得できたとして > [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]]]; > でサイトはオフラインで開けるのでしょうか? この質問の意味があまりちゃんと理解できてないのですが、 サンプルプロジェクトでキャッシュしたデータはどこに保存されているか? という意味でしたら、 RNCachingURLProtocol.mのcachePathForRequestメソッドで リクエストURLに対応するキャッシュファイル名を求めているので その処理を確認すればよいと思います。 また、このキャッシュファイルにデータを書きだす処理は RNCachingURLProtocol.mのconnection:willSendRequestメソッドの [NSKeyedArchiver archiveRootObject:cache toFile:cachePath]; の部分です。 そして、キャッシュファイルからデータを読み込む処理は RNCachingURLProtocol.mのstartLoadingメソッドの RNCachedData *cache = [NSKeyedUnarchiver unarchiveObjectWithFile:[self cachePathForRequest:[self request]]]; になります。 このあたりが理解できればキャッシュを読み書きする処理も 自分の好きなように作れると思います。 ただ、このサンプルプロジェクトはかなり難しいので、本当に理解するには 「URLローディングシステムプログラミングガイド」 https://developer.apple.com/jp/devcenter/ios/library/documentation/URLLoadingSystem.pdf をちゃんと読んだ方がよいと思います。
その他の回答 (1)
- Lchan0211b
- ベストアンサー率61% (573/930)
質問に書かれているdownloadHTMLメソッドとrefreshメソッドを使って ごく簡単なHTMLファイルをキャッシュし、オフラインで表示してみましたが 問題なく表示されましたよ。 ただ、このコードは、HTMLファイル内の画像リンク(img srcタグ)等、 別ファイルで定義されている情報を自動的に読み込んでキャッシュする 機能はありません。 したがって、画像ファイルのあるWebページやCSSファイル/JavaScriptファイルを 使ったページ等、要するに一般的なWebサイトには対応できないと思います。 また、 > 表示されたサイトは(オンライン時)スマートフォン向けだったページがPC版の表示で表示されました。 この原因は、NSURLRequestでリクエストする時のUser-Agentが 「User-Agent: (アプリ名)/(ver.) CFNetwork/(ver.) Darwin/(ver.)」 という形式になるため、iPhoneのブラウザからのアクセスではなく アプリからの独自リクエストと認識されたためだと思います。 (User-Agentのことを知らなければ検索してください) で、一般的なWebサイトの情報をiPhoneからアクセスした形でローカルに 保存したいということであれば、質問の最後に書かれてあった http://qiita.com/EntreGulss/items/8da6847e4dae59bfb1eb の方法で実装する必要があると思います。 質問では、この方法でもオフラインで表示されなかったとのことですが、 この記事は概要が書かれてあるだけで、実際にはその記事から リンクされている https://github.com/EntreGulss/CachedWebpage のサンプルプロジェクトをダウンロードして実行するだけだと思います。 実際に私の方でダウンロード/実行してみたところ、古いプロジェクトなので AutoLayoutの使用でエラーが出たりしましたが、AutoLayoutの使用をOFFに すれば、普通に実行できて、一般的なyahoo等のWebページをキャッシュし オフラインで表示できました。 なお、このサンプルは通信経路があるかどうかを「Reachability」という クラスを使って判断し、通信経路がない場合だけキャッシュから読み込みますから 一度Webサイトにアクセスした後、機内モードに変更する等した上で 再読み込みボタンを押す必要があります。 そうするとキャッシュから読まれます。 あと、JavaScriptを使ってページ内で追加データを取得するようなケースには このサンプルでも当然対応できませんから、うまく表示されない時は 問題のWebページがどのような内容になっているか調べる必要があると思います。
補足
回答ありがとうございます。 iOSシミュレータでは機内モードができずずっとPCのWIFIを切って実行していたのでそれが原因だったと思います。 私はまだ実機でテストできる環境ではないのでキャッシュを読み込めるならhttp://qiita.com/EntreGulss/items/8da6847e4dae59bfb1ebのやり方で作業の方を進めていこうと思います。 そこで、取得した特定のキャッシュをNSUserDefaultなどに入れておき自由に取り出せるようキャッシュのパスを取得→保存→取り出し→読み込みをしたいと思います。 http://d.hatena.ne.jp/ntaku/20110104/1294146555にキャッシュが保存されるというキャッシュディレクトリのパスがありました。 NSArray *paths = NSSearchPathForDirectoriesInDomains(NSCachesDirectory, NSUserDomainMask, YES); NSString *dir = [paths objectAtIndex:0]; ここから特定のキャッシュのパスを取得するにはどうしたらいいでしょうか? またパスを取得できたとして [self.webView loadRequest:[[NSURLRequest alloc] initWithURL:[NSURL URLWithString:path]]]; でサイトはオフラインで開けるのでしょうか? 差し支えなければ回答お願いします。
お礼
質問が分かりにくくなってしまってすみません。 でもなんとか意図は伝わっているようなので良かったです。 わざわざそちらでテストまでしてもらってありがとうございます。 あとは何とか自分でやってみようと思います。