ASIHTTPRequestに必要なframeworkたち

iPhoneアプリでHttpリクエストを使う場合には必須なライブラリ、ASIHTTPRequestの必須frameworkがオフィシャルのサイトに書いてあるのだけでは動かないのでメモメモ。

もう毎回忘れちゃうんですが、
How to use ASIHTTPRequest in your projects – All-Seeing Interactive
に書かれている、

Repeat the last two steps to add the following: SystemConfiguration.framework, MobileCoreServices.framework, CoreGraphics.framework and libz.dylib.

via: How to use ASIHTTPRequest in your projects – All-Seeing Interactive

これだけでは実際には動かないです。

  1. SystemConfiguration.framework
  2. MobileCoreServices.framework
  3. CoreGraphics.framework
  4. libz.dylib
  5. CFNetwork.framework

最後のCFNetwork.frameworkがないと動かないのです!

ファミ通App iPhone&Android NO.004 (エンターブレインムック)
エンターブレイン (2012-10-18)
売り上げランキング: 22

WebViewのCookieをネイティブ側のリクエストで使う方法(iPhone・Android)

iPhone版

CookieをiPhone側でセット/削除する方法 – 風日記
iphone – Where are an UIWebView’s cookies stored? – Stack Overflow
を見た。

iPhone側はすごく簡単で、WebViewでリクエストを投げると、それだけでASIHTTPRequest(ネイティブ)のリクエストと共有されていた。
Cookieの内容を確認するにはNSHTTPCookieStorageを使うとすぐに見ることができる。

サンプル・コード

NSHTTPCookie *cookie;
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (cookie in [cookieJar cookies]) {
    NSLog(@"%@", cookie);
    if ([@"lab.hisasann.com" isEqualToString:cookie.domain]) {
        NSLog(@"name - %@", cookie.name);
        NSLog(@"value - %@", cookie.value);
    }
}

gist

iPhoneでWebViewのCookieを共有する方法 — Gist


Android版

Androidのほうはやや複雑、WebViewのリクエストが完了するイベントで、すでにインスタンス化してあるHttpClientに対して、Cookieをaddしないといけない。
これをしないと、HttpClient(ネイティブ)のリクエストにCookieが乗ってくれない。

サンプル・コード

webview.setWebViewClient(new WebViewClient() {
    @Override
    public void onPageFinished(WebView view, String url) {
  System.out.println("onPageFinished - " + url);
  super.onPageFinished(view, url);

  // Cookieの保存が予想されるURLの場合
  if (url.indexOf("http://lab.hisasann.com/") > -1) {
      // WebViewのCookieを取得
      String cookie = CookieManager.getInstance().getCookie(url);
      System.out.println("cookie - " + cookie);
      String[] cookies = cookie.split(";");
      for (String keyValue : cookies) {
    keyValue = keyValue.trim();
    String[] cookieSet = keyValue.split("=");
    // Cookieを作成
    BasicClientCookie bCookie = new BasicClientCookie(cookieSet[0], cookieSet[1]);
    bCookie.setDomain("lab.hisasann.com");
    bCookie.setPath("/");
    // CookieStoreを取得
    CookieStore store = httpClient.getCookieStore();
    // Cookieを追加
    store.addCookie(bCookie);
      }
  }
    }
});

Cookieの内容を確認するにはCookieStoreを使うとすぐに見ることができる。

サンプル・コード

CookieStore store = httpClient.getCookieStore();
List<Cookie> cookies = store.getCookies();
for (Cookie cookie : cookies) {
    // クッキーの設定
    if ("lab.hisasann.com".equals(cookie.getDomain())) {
  // クッキーを再設定
  System.out.println(cookie.getName() + "=" + cookie.getValue());
  break;
    }
}

つまり、ひとつのHttpClientインスタンスにCookieをセットしているので、複数のHttpClientをnewする場合は、それぞれにCookieを入れないとダメっぽい。

gits

AndroidでWebViewのCookieを共有する方法 — Gist

どうでもいいことだが

iPhoneの

NSURL *url = [NSURL URLWithString:@"http://lab.hisasann.com/cookie/setcookie.php"];

http:/でも動いた。つまりスラッシュが一個足りない!

Androidではダメでした。

iOS6から搭載されたUIRefreshControl(PullToRefresh)がかっこいい!

iOS6のメーラーを使っていると、PullToRefreshがプニョ〜っと伸びる感じが気持ちいいなーと思っていたら、UIRefreshControlという名前だった。

iOS6から搭載されたUIRefreshControl(PullToRefresh)がかっこいい!

サンプルコード

使い方はすごく簡単で、UITableViewControllerのrefreshプロパティかUIScrollViewにaddSubviewするかみたい。
今回はUIScrollViewのほうで書いてみました。

- (void)viewDidLoad {
    [super viewDidLoad];

    NSString *string = @"PullToRefresh";

    _refreshControl = [[UIRefreshControl alloc] init];
    [_refreshControl addTarget:self action:@selector(refresh:) forControlEvents:UIControlEventValueChanged];

    // 色
    NSMutableDictionary *dictionary = [NSMutableDictionary dictionary];
    [dictionary setObject:[UIColor whiteColor] forKey:NSForegroundColorAttributeName];
    NSMutableAttributedString *attributedString = [[NSMutableAttributedString alloc] initWithString:string attributes:dictionary];

    // Font
    [attributedString addAttribute:NSFontAttributeName value:[UIFont fontWithName:@"Helvetica-Bold" size:30.0f] range:NSMakeRange(0, string.length)];
    [attributedString addAttribute:NSStrokeColorAttributeName value:[UIColor redColor] range:NSMakeRange(0, string.length)];
    [attributedString addAttribute:NSStrokeWidthAttributeName value:[NSNumber numberWithFloat:3.0] range:NSMakeRange(0, string.length)];
    _refreshControl.attributedTitle = attributedString;

    [self.scrollView addSubview:_refreshControl];
    self.scrollView.contentSize = CGSizeMake(320, 2000);
}

リフレッシュが起動したときのタイミングでこのメソッドが呼ばれます。

- (void)refresh:(id)sender {
    [NSTimer scheduledTimerWithTimeInterval:1.f target:self selector:@selector(endRefresh) userInfo:nil repeats:NO];
}

んで、何かリクエストして、そのコールバックあたりで以下を呼び出せばいいのではないでしょうか。

- (void)endRefresh {
    [_refreshControl endRefreshing];
}

簡単ですね!

関連リンク

iPhoneプログラミングUIKit詳解リファレンス
所 友太
リックテレコム
売り上げランキング: 13490

iPhoneアプリをAdHocアプリとして配布するのは実は超絶簡単だった

はじめ、
Xcode4でのAdHocアプリ(ipa)の作成方法詳解 – iPhoneアプリ開発まっしぐら★ – iPhoneアプリ開発グループ
こちらの記事を参考にしてやっていたのですが、すぐに
じつはもっと簡単なAdHocアプリ(ipa)の作成方法があった件… for Xcode4 – iPhoneアプリ開発まっしぐら★ – iPhoneアプリ開発グループ
こちらの記事を見て、すごく簡単ということでここにもメモしておきます。

事前に、

  • Distribution用のプロビジョニングファイル
  • プロビジョニングファイルを作った人のMac上で作られた秘密鍵ファイル(証明書.p12)

をMacにインストールしておく。

  1. XCodeのOrganizerを開きます
  2. Archivesを開きます
  3. Distributeボタンを押す
  4. Save for Enterprise or Ad-Hoc Deploymentにチェックを入れる
  5. Code Signing IdentityにDistribution用のプロビジョニングファイルをを選択する
  6. ipaファイルの保存場所を決める

これだけ。
プロビジョニングファイルをこちら側で用意できない場合はこの方法が使えます。

iPhoneアプリ開発塾
iPhoneアプリ開発塾
posted with amazlet at 12.10.29
カワサキ タカシ
技術評論社
売り上げランキング: 2513

AppとWebViewの相互の機能の呼び方、そしてhistory.back()について(iPhone・Android)

history.back()が出来る状況が毎度毎度分からなくなってしまうので、ここにまとめておきます。
また、AppからWebViewの機能を呼ぶ、WebViewからAppの機能を呼ぶということもどうゆう状況だとできるのかもまとめておきます。
むしろこっちのほうが忘れやすい。

history.back()

ローカルHTMLファイルの場合

iPhone 動かない
Android 動く

リモートHTMLファイルの場合

iPhone 動く
Android 動く

なので、history.back()を前提にしているjQueryMobileを使うサイトは、ローカルではなくリモートを参照したほうがいいでしょう。


Titanium.App.fireEvent

ここはTitaniumのfireEventが動く範囲をまとめてみました。

ローカルHTMLファイルの場合

iPhone 動く
Android 動く

リモートHTMLファイルの場合

iPhone 動かない
Android 動かない

iPhoneとWebView

ここからはネイティブの話しになります。

iPhoneでアプリ側からWebViewに対してJavaScriptを実行する方法

「App → WebView」

WebViewをもつViewControllerのヘッダファイルにて、UIWebViewDelegateプロトコルを指定しておく。

@interface ViewController : UIViewController <UIWebViewDelegate>

すると以下のメソッドたちが使えるので、準備しておく。

- (void)webViewDidStartLoad:(UIWebView *)webView {
}

- (void)webViewDidFinishLoad:(UIWebView *)webView {
}

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
    return YES; // Return YES to make sure regular navigation works as expected.}
}

あとはstringByEvaluatingJavaScriptFromStringを呼び出すだけ。

- (void)webViewDidFinishLoad:(UIWebView *)webView {
    NSString *title = [self.webView stringByEvaluatingJavaScriptFromString:@"$.method()"];
    NSLog(@"title - %@", title);
}

このメソッドの便利なところは、returnがあるところ、後述するがAndroidのほうだとreturnが返ってこないので、少し強引に取得する必要があったりする。

WebViewからiPhoneアプリ側に処理を通知する方法

「WebView → App」

こっちはURLのリクエスト時に、自分宛、つまり自分のアプリ内で処理して欲しいURLを渡して、それを監視している。
結果、ルールにのっとったURLの場合は、適切な処理を呼べば良い。

面白いところは、自分宛のリクエストはreturn NOを返してなかったことにしている。
これをしないと、真っ白な画面に遷移してしまう。

- (BOOL)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType {
  NSString *requestString = [[request URL] absoluteString];
  NSArray *components = [requestString componentsSeparatedByString:@":"];

  if ([components count] > 1 &&
        [(NSString *) [components objectAtIndex:0] isEqualToString:@"myapp"]) {
    if ([(NSString *) [components objectAtIndex:1] isEqualToString:@"myfunction"]) {
      // ここで何か処理
      NSLog(@"%@", [components objectAtIndex:2]); // param1
      NSLog(@"%@", [components objectAtIndex:3]); // param2
    }
    return NO;
  }

  return YES; // Return YES to make sure regular navigation works as expected.}
}

WebViewからの呼び出し方。

location.href = "myapp:" + "myfunction:" + param1 + ":" + param2;

比較的にシンプルにできるが、ディレクトリトラバーサルなど、セキュリティに気をつける必要がある。


AndroidとWebView

Androidでアプリ側からWebViewに対してJavaScriptを実行する方法

iPhone型と違って、view.loadUrlにjavascriptスキームを渡してもreturnが得られません。
なので、ハックに近いですが、あえてalertを実行させ、そのアラートが出る前のイベントonJsAlertでメッセージから情報を取得します。
そのあとに、result.confirm()をすることで、アラートがなかったことにできるようです。

なかなか面白いですね。

WebView webview = (WebView) findViewById(R.id.webView1);
webview.getSettings().setJavaScriptEnabled(true);

webview.setWebViewClient(new WebViewClient() {
  @Override
  public void onPageFinished(WebView view, String url) {
    view.loadUrl("javascript:alert($.method())");
  }
});
webview.setWebChromeClient(new WebChromeClient() {
  @Override
  public boolean onJsAlert(WebView view, String url, String message, JsResult result) {
    try {
      System.out.println("onJsAlert - " + message);

      return true;
    } finally {
      // アラートが出ないようにしている
      result.confirm();
    }
  }
});

webview.loadUrl("http://lab.hisasann.com/appEval/");

WebViewからAndroidアプリ側に処理を通知する方法 – その1

WebViewからAndroidアプリ側に情報を渡すのは以下の感じで、iPhone側とすごく似ていますね。
ただ、Androidのほうは直接JavaScriptコードからAndroid側のアプリをキックできるようです。

それは後述します。

webview.setWebViewClient(new WebViewClient() {
  @Override
  public boolean shouldOverrideUrlLoading(WebView view, String url) {
    String[] components = url.split(":");

    // 特定のURLの場合、ダイアログを表示する等
    if (components[0].length() > 1 && "myapp".equals(components[0])) {
        if ("myfunction".equals(components[1])) {
          System.out.println(components[2]);
          System.out.println(components[3]);

          return true;
        }
    }

    return false;
  }
});

WebViewからの呼び出し方。

location.href = "myapp:" + "myfunction:" + param1 + ":" + param2;

WebViewからAndroidアプリ側に処理を通知する方法 – その2

先ほどのwebview変数にJavascriptInterfaceをセットします。

webview.addJavascriptInterface(new JavascriptAdapter(), "android");

そのアダプターの中で、JavaScriptから呼び出されるメソッドを定義しておきます。

package com.example.sample_webvieweval;

import android.os.Handler;

public class JavascriptAdapter {
  private Handler handler = new Handler();

  // JavaScriptから呼び出されるメソッド
  public void getFromJS(final String s) {
    handler.post(new Runnable() {
        public void run() {
          System.out.println(s);
        }
    });
  }
}

WebViewからの呼び出し方。

// Javaのメソッドを呼び出す
window.android.getFromJS("called getFromJS");

するとこのようにwindowオブジェクトの中にJavascriptInterfaceの名前空間が追加されているので、そこから呼びたいメソッドをコールできます。

すごく簡単!
すごく簡単なんだけど、やっぱりこれもセキュリティをかなり意識しないといけないですね。

参考リンク

本格アプリを作ろう! Androidプログラミングレシピ
Dave Smith Jeff Friesen
インプレスジャパン
売り上げランキング: 13499