2014年2月10日月曜日

[android]javax.net.ssl.SSLException発生

とあるWeb API(https)が突然使えなくなりました。
  • 先月までは大丈夫だった(通信できていた)気がします
  • javax.net.ssl.SSLExceptionが発生するようになりました
  • 私が所有している端末のうち、android2.2のみで不具合が起きていました
  • org.apache.http.impl.client.DefaultHttpClientを使って実装していました
org.apache.http.impl.client.DefaultHttpClientはandroidでは推奨されていないのですね……
私が利用させていただいているWeb API(https)では、javax.net.ssl.HttpsURLConnectionを使うと通信できるようになりましたので、そのときのソースを書いておきます。
try {
    URL url = new URL("https/......");
    HttpsURLConnection urlConnection = null;
    try {
        urlConnection = (HttpsURLConnection) url.openConnection();
        SSLContext context = SSLContext.getInstance("TLS");
        TrustManager tm = new X509TrustManager() {
            @Override
            public void checkClientTrusted(X509Certificate[] chain,
                String authType) throws CertificateException {
            }

            @Override
            public void checkServerTrusted(X509Certificate[] chain,
                String authType) throws CertificateException {
            }

            @Override
            public X509Certificate[] getAcceptedIssuers() {
                return null;
            }
        };
        context.init(null, new TrustManager[] { tm }, null);
        urlConnection.setSSLSocketFactory(context.getSocketFactory());
        InputStream in = urlConnection.getInputStream();
        if (urlConnection.getResponseCode() == HttpURLConnection.HTTP_OK) {
                // 通信成功!!!
                // inを煮るなり焼くなりしてください!
        }
    } catch (IOException e) {
        e.printStackTrace();
    } catch (NoSuchAlgorithmException e) {
        e.printStackTrace();
    } catch (KeyManagementException e) {
        e.printStackTrace();
    } finally {
        urlConnection.disconnect();
    }
} catch (MalformedURLException e) {
    e.printStackTrace();
}

2014年2月6日木曜日

ありがとう

JavaScriptのイベントを勉強しました

2014年1月11日土曜日

[android][Java]雑談対話

docomo Developer support様の雑談対話APIを使ったandroidアプリケーションを作ってみました。
雑談対話APIはHttpPostを使う必要があります。
これまでHttpGetを使うWeb APIはいくつか使ったことがあったのですが、HttpPostはあまり経験がなくて苦戦してしまいました。
なんとかできましたので、その時のメモを残しておきます。
苦戦したポイントは……(いやーお恥ずかしい)
  • <uses-permission android:name="android.permission.INTERNET" />を忘れずに
  • JSON形式でリクエストを送らないといけないことになかなか気づかなかったこと
  • StringEntityのコンストラクタで第2引数 "UTF-8"が必要だったこと(機種依存なのかも? しれません)

参考にさせていただいたサイト様です。

HttpPostリクエストを実行して、HttpResponseを得るところまでのソースです。
AsyncTask#doInBackground()等main threadではないThreadで動作するように実装すればよいかとおもいます。
DefaultHttpClient httpclient = new DefaultHttpClient();
final String APIKEY = "ご自身のAPIKEYをお使いください";
HttpPost post = new HttpPost("https://api.apigw.smt.docomo.ne.jp/dialogue/v1/dialogue?APIKEY=" + APIKEY);
JSONObject json = new JSONObject();
try {
    json.put("utt", "こんにちは");
    StringEntity body = new StringEntity(json.toString(), "UTF-8"); /** LYNX 3D SH-03Cは第2引数"UTF-8"が必要でした。 */
    //post.addHeader("Content-Type", "application/json"); /** 雑談対話APIでは設定をしなくてもよいようです。 */
    post.setEntity(body);
    HttpResponse response = httpclient.execute(post);
    int statusCode = response.getStatusLine().getStatusCode();
    if (statusCode == HttpStatus.SC_OK) {
        HttpEntity entity = response.getEntity();
        String jsonTxt = EntityUtils.toString(entity, "UTF-8");
        JSONObject response_json = new JSONObject(jsonTxt);
        /** レスポンスの取り出し */
        String utt = response_json.getString("utt");
        String yomi = response_json.getString("yomi");
        String mode = response_json.getString("mode");
        String da = response_json.getString("da");
        String context = response_json.getString("context");
    }
} catch (ClientProtocolException e) {
} catch (IOException e) {
} catch (JSONException e) {
}

2014年1月1日水曜日

[android]NFC

あけましておめでとうございます。
今年もよろしくお願いします。

ABC 2013 Autumnに行ったときに記念に買ったNFCタグ(100円)に情報を書き込んでみたくなりました。
秋に買ったときは対応端末を何も持っていなかったので、ずっと引き出しの奥に眠ったままになっていました。
 ↑↑↑
こんなやつです。

Nexus 5を買ったのでかざしてみました。
「なにも書き込まれていません」みたいな表示がされました。

何か書き込んでみたくなりました。
http://developer.android.com/guide/topics/connectivity/nfc/index.html
を読んでいろいろやってみましたが、できませんでした……

http://www.ntts.co.jp/publish/column/tec/mobile_04/index.html
わかりやすく解説してくださっているページがありましたので、そのとおりにやるとできました。
URL情報がNFCタグに書き込まれて、かざすとそのページがブラウザで開けるようになりました。

もう一回公式の内容を読み返してみたいとおもいます。
今度は話がつながってくるような気がします。


追伸
Nexus 5いいです。Google Playで買いました。
ビックカメラSIM(SMS)との組み合わせが一番いいんじゃないでしょうか。


追伸2
『インフラエンジニアの教科書』をある人からススメられて読みました。
いろいろ勉強せんといかんですね。


2013年11月10日日曜日

[android]ファイル圧縮による通信量の削減

NTT docomo様ご提供の「AndroidTMアプリ作成ガイドライン~効率的な通信制御に向けて~」を読みました。


PDF内の「3.4.5. ファイル圧縮による通信量の削減」をやってみました。
携帯ネットワークの効率的な利用に対して、私にもすぐに貢献できそうだとおもったからです。
(まあ、私のアプリの通信なんて微々たるものだとはおもいますが……)
PDF内のサンプルコードHTTP GET時にGZIP要求を行うクラス(AsyncHttpGet2)の内容そのままです。

HttpResponseインスタンスを得るところまでをちょっと変更させてもらうと、
HttpClient httpClient = new DefaultHttpClient();
HttpGet httpGet = new HttpGet("WEB APIのリクエストURL");
Header[] headers = new Header[2];
headers[0] = new BasicHeader("Accept-Encoding", "gzip, deflate");
headers[1] = new BasicHeader("User-Agent", "my program (gzip)");/** ★ */
httpGet.setHeaders(headers);
HttpResponse response = httpClient.execute(httpGet);
/** responseがGZIP圧縮されている場合は、GZIPInputStreamで受け取る */
/** PDFのサンプルコードがとても参考になります! */

★の("User-Agent", "my program (gzip)")は通信するサーバによっては不要だとおもいます。
Google様のWEB APIを使うときは必要なようです。
たとえばYouTube Data APIには、gzipを含むUser-Agentの指定が必要なことが明記されています。
gzipを含んだUser-Agentを指定しないと、GZIP圧縮された返戻を得られませんでした。
Google App Engineで作った自作のWEB APIでも同様だったので、Google様で共通の仕様なのかもしれません。




2013年11月6日水曜日

GAE(Java)のプロジェクトが変になった



SDKが初期化できないとかなんとかという現象でした。

ちょうどこことかここにあるような内容と同じ現象でした。
cleanができない、プロジェクトに赤いびっくりマーク(!)が表示される……
泣きそうでした。


なにを契機におかしくなったのかは不明です。
なんとか復活できましたので、その内容をメモしておきます。

【環境】
パソコン: iMac 21.5-inch, Late 2012
    プロセッサ 2.7GHz Intel Core i5
                メモリ 8 GB 1600 MHz DDR3
OS: Mac OSX 10.9 Mavericks
Eclipse: バージョン4.2.2
Java: Java 6

【対処概要】
Java 7をインストールする。
Warning: The App Engine SDK no longer supports Java 6. Applications that use Java 6 need to be migrated to Java 7. Existing applications that use the Java 6 runtime are still supported, but this support will be removed in a future release.
なのだそうです。

【メモ】
1. JDK 7のインストール
ここを参考にさせていただきました。ありがとうございます。
「(4) 環境変数を設定する」はやっていないです。よくわからなかったので。
「(5) システムのJavaを設定する。」もやっていないです。
そのかわり、java -versionとかjavac -versionとかやったら、
Java 7(1.7.0_45)に変わっていることは確認しました。
(※)MacでのJava Preferencesは、ここにあるようです。
 ある時点から、アプリケーション->ユーティリティ配下ではなくなったようです。
  リンゴマーク(左上)→システム環境設定…


2. プロジェクトを修正する
・右クリック(※) ⇒ Properties -> Google -> App Engine
 Use specific SDKを正しいものに選びなおす。

・右クリック ⇒ Properties -> Java Build Path -> Librariesで×マークになっているものを
 Removeする。
 ⇒ プロジェクト欄の赤いびっくりマーク(!)は消えました。
   しかし、Project -> Cleanしてもまだなにやらエラーがでていました。
     あと一歩です!
Exception in thread "main" java.lang.UnsupportedClassVersionError: com/google/appengine/tools/enhancer/Enhance : Unsupported major.minor version 51.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClassCond(ClassLoader.java:637)
at java.lang.ClassLoader.defineClass(ClassLoader.java:621)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:141)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:283)
at java.net.URLClassLoader.access$000(URLClassLoader.java:58)
at java.net.URLClassLoader$1.run(URLClassLoader.java:197)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:190)
at java.lang.ClassLoader.loadClass(ClassLoader.java:306)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:301)
at java.lang.ClassLoader.loadClass(ClassLoader.java:247)


・JREの設定
 ⇒ こちらがJava 6のままだったから不都合が起きていたようです。

      Eclipse(※) -> 環境設定… -> Java -> Insitalled JREs
     (※)リンゴの隣です。Windows PCの場合は、Window -> Preferencesだったとおもいます。
      jre6にチェックがついていました。
      Searchボタンを押すと、jre7が見つかったので、チェックをつけてOK。

だいたいこんな感じで、再びcleanや実行、deployができるようになりました!

他にはORACLE様のFAQが参考になりそうなのでリンクを紹介しておきます。

(※)生粋のMacユーザさん達は右クリックなんてしないのですかね。
私はマウスの設定で右クリックを有効にしています。慣れた操作なので、私にはしっくりきます。