[Mac] Finder の環境設定メモ [2013年版]
- 2013 6/29
Android アプリで、Google Analytics を使うために参考にした情報をまとめました。
・Google Analytics SDK for Android v2 (Beta) – Overview
Google Play のダウンロードがどこ経由かトラッキングするためのキャンペーンのパラメータ付きURLを簡単に生成できるツール
・Campaign Measurement – Android SDK – Google Analytics
・① 「概要」
・②「高度な設定」
・③「キャンペーントラッキング」
・④「クラッシュと例外」
・⑤「ディスパッチング」
・⑥「eコマーストラッキング」
・⑦「イベント」
・⑧「スクリーン」
・⑨「セッション」
・⑩「ユーザータイミング」
・⑪「EasyTrackerパラメータ」
Facebook SDK for Android v3.0 でログイン処理時に NullPointerException エラーが発生しました。
Stack Trace 0 java.lang.RuntimeException: Failure delivering result ResultInfo{who=null, request=64206, result=0, data=null} to activity {com.example/com.facebook.LoginActivity}: java.lang.NullPointerException 1 at android.app.ActivityThread.deliverResults(ActivityThread.java:2980) 2 at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023) 3 at android.app.ActivityThread.access$1100(ActivityThread.java:123) 4 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177) 5 at android.os.Handler.dispatchMessage(Handler.java:99) 6 at android.os.Looper.loop(Looper.java:137) 7 at android.app.ActivityThread.main(ActivityThread.java:4424) 8 at java.lang.reflect.Method.invokeNative(Native Method) 9 at java.lang.reflect.Method.invoke(Method.java:511) 10 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 11 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 12 at dalvik.system.NativeStart.main(Native Method) 13 Caused by: java.lang.NullPointerException 14 at com.facebook.AuthorizationClient$KatanaProxyAuthHandler.onActivityResult(SourceFile:645) 15 at com.facebook.AuthorizationClient.onActivityResult(SourceFile:142) 16 at com.facebook.LoginActivity.onActivityResult(SourceFile:134) 17 at android.app.Activity.dispatchActivityResult(Activity.java:4676) 18 at android.app.ActivityThread.deliverResults(ActivityThread.java:2976) 19 ... 11 more 20 java.lang.NullPointerException 21 at com.facebook.AuthorizationClient$KatanaProxyAuthHandler.onActivityResult(SourceFile:645) 22 at com.facebook.AuthorizationClient.onActivityResult(SourceFile:142) 23 at com.facebook.LoginActivity.onActivityResult(SourceFile:134) 24 at android.app.Activity.dispatchActivityResult(Activity.java:4676) 25 at android.app.ActivityThread.deliverResults(ActivityThread.java:2976) 26 at android.app.ActivityThread.handleSendResult(ActivityThread.java:3023) 27 at android.app.ActivityThread.access$1100(ActivityThread.java:123) 28 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1177) 29 at android.os.Handler.dispatchMessage(Handler.java:99) 30 at android.os.Looper.loop(Looper.java:137) 31 at android.app.ActivityThread.main(ActivityThread.java:4424) 32 at java.lang.reflect.Method.invokeNative(Native Method) 33 at java.lang.reflect.Method.invoke(Method.java:511) 34 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:784) 35 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:551) 36 at dalvik.system.NativeStart.main(Native Method) |
Facebook SDK for Android v3.0 のバグらしいので、v3.0.1 にアップデートすることで解決します。
Node.js で、コマンドライン引数をカンタンに扱えるモジュール「commander.js」がとても便利です!
Node.js で HTTPS リクエストを生成するコードで [Error: socket hang up] code: ‘ECONNRESET’ というエラーが発生しました。
エラーメッセージ
Error: socket hang up at createHangUpError (http.js:1124:15) at Socket.socketOnEnd [as onend] (http.js:1272:23) at TCP.onread (net.js:389:26) |
HTTPS リクエストを送るのに、https モジュールじゃなく http モジュールを使っていたのが原因でした…
なので、下記のようにちゃんと https モジュールを使えばOKです。
var https = require('https'); /** * HTTPS POST (JSON) * * @param {Object} jsonData * @param {Function} callback * @param {String} encoding */ function httpJsonPost(jsonData, callback, encoding) { jsonData = jsonData || {}; encoding = encoding || 'utf8'; var jsonDataString = JSON.stringify(jsonData); var headers = { 'Content-Type': 'application/json', 'Content-Length': jsonDataString.length }; var options = { host: 'api.example.com', port: 443, path: '/1/push', method: 'POST', headers : headers }; var req = https.request(options, function(res) { res.setEncoding(encoding); var responseString = ''; res.on('data', function(chunk) { responseString += chunk; }); res.on('end', function() { var resultObject = JSON.parse(responseString); return callback(null, resultObject, res.statusCode, JSON.stringify(res.headers)); }); }); req.on('error', function(e) { return callback(e); }); req.write(jsonDataString); req.end(); } |
[参考情報]
Parse.com の REST API でプッシュ通知配信する curl コマンドを用途別にご紹介します。
[参考]: Push Developer Guide | Parse
全てのアプリにプッシュ通知配信
curl -X POST \ -H "X-Parse-Application-Id: xxxxxxxxxx" \ -H "X-Parse-REST-API-Key: xxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "data": { "alert": "This is a notification message!" } }' \ https://api.parse.com/1/push |
Android アプリにプッシュ通知配信
curl -X POST \ -H "X-Parse-Application-Id: xxxxxxxxxx" \ -H "X-Parse-REST-API-Key: xxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "where": { "deviceType": "android", }, "data": { "alert": "This is a notification message!" } }' \ https://api.parse.com/1/push |
iOS アプリにプッシュ通知配信 [2013年6月26日23時00分(現地時間)]
curl -X POST \ -H "X-Parse-Application-Id: xxxxxxxxxx" \ -H "X-Parse-REST-API-Key: xxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "where": { "deviceType": "ios", }, "push_time": "2013-06-26T23:30:00", "data": { "alert": "This is a notification message!" } }' \ https://api.parse.com/1/push |
iOS アプリにプッシュ通知配信 [2013年6月26日23時00分(現地時間)]
かつ、アプリ側で notificationTime を 23:30 を設定するもののみに、プッシュ通知配信
curl -X POST \ -H "X-Parse-Application-Id: xxxxxxxxxx" \ -H "X-Parse-REST-API-Key: xxxxxxxxxx" \ -H "Content-Type: application/json" \ -d '{ "where": { "deviceType": "ios", "notificationTime": "23:30" }, "push_time": "2013-06-26T23:30:00", "data": { "alert": "This is a notification message!" } }' \ https://api.parse.com/1/push |
Android アプリ開発にて、ListFragment で setListAdapter した後に addHeaderView や addFooterView を呼び出すと java.lang.IllegalStateException 例外が発生して、アプリがクラッシュしてしまいます。
Android 4 系だと例外は発生しなくて、Android 2.3 系だと例外でクラッシュするみたいです。
Stack Trace _________________________________ 0 java.lang.RuntimeException: Unable to resume activity {com.example/com.example.activity.MainActivity}: java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called. 1 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2124) 2 at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139) 3 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961) 4 at android.os.Handler.dispatchMessage(Handler.java:99) 5 at android.os.Looper.loop(Looper.java:123) 6 at android.app.ActivityThread.main(ActivityThread.java:3691) 7 at java.lang.reflect.Method.invokeNative(Native Method) 8 at java.lang.reflect.Method.invoke(Method.java:507) 9 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864) 10 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622) 11 at dalvik.system.NativeStart.main(Native Method) 12 Caused by: java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called. 13 at android.widget.ListView.addHeaderView(ListView.java:336) 14 at android.widget.ListView.addHeaderView(ListView.java:359) 15 at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358) 16 at com.example.fragment.NewFragment.onResume(NewFragment.java:143) 17 at android.support.v4.app.Fragment.performResume(Fragment.java:1503) 18 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947) 19 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088) 20 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070) 21 at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871) 22 at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455) 23 at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444) 24 at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69) 25 at android.app.Activity.performResume(Activity.java:3867) 26 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114) 27 ... 10 more 28 java.lang.IllegalStateException: Cannot add header view to list -- setAdapter has already been called. 29 at android.widget.ListView.addHeaderView(ListView.java:336) 30 at android.widget.ListView.addHeaderView(ListView.java:359) 31 at com.example.fragment.NewFragment.refreshListView(NewFragment.java:358) 32 at com.example.fragment.NewFragment.onResume(NewFragment.java:143) 33 at android.support.v4.app.Fragment.performResume(Fragment.java:1503) 34 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:947) 35 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1088) 36 at android.support.v4.app.FragmentManagerImpl.moveToState(FragmentManager.java:1070) 37 at android.support.v4.app.FragmentManagerImpl.dispatchResume(FragmentManager.java:1871) 38 at android.support.v4.app.FragmentActivity.onResumeFragments(FragmentActivity.java:455) 39 at android.support.v4.app.FragmentActivity.onPostResume(FragmentActivity.java:444) 40 at com.actionbarsherlock.app.SherlockFragmentActivity.onPostResume(SherlockFragmentActivity.java:69) 41 at android.app.Activity.performResume(Activity.java:3867) 42 at android.app.ActivityThread.performResumeActivity(ActivityThread.java:2114) 43 at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:2139) 44 at android.app.ActivityThread$H.handleMessage(ActivityThread.java:961) 45 at android.os.Handler.dispatchMessage(Handler.java:99) 46 at android.os.Looper.loop(Looper.java:123) 47 at android.app.ActivityThread.main(ActivityThread.java:3691) 48 at java.lang.reflect.Method.invokeNative(Native Method) 49 at java.lang.reflect.Method.invoke(Method.java:507) 50 at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:864) 51 at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:622) 52 at dalvik.system.NativeStart.main(Native Method) |
正しいコード
// addHeaderView 後に setListAdapter listView.addHeaderView(headerView); listView.addFooterView(footerView); setListAdapter(arrayAdapter); |
IllegalStateException でクラッシュするコード
// setListAdapter 後に addHeaderView setListAdapter(arrayAdapter); listView.addHeaderView(headerView); listView.addFooterView(footerView); |
必ず setListAdapter する前に、addHeaderView や addFooterView を呼び出すようにしましょう。
[参考]
・Note to self: ListFragment and header views
・android – ListFragment add headerView gives java.lang.IllegalStateException:alled – Stack Overflow
・Android – ListActivity, add Header and Footer view – Stack Overflow
・android – How to add footer view dynamically – Stack Overflow
開発中の Android アプリが、下記のエラーでクラッシュしました。
RuntimeException: Can't create handler inside thread that has not called Looper.prepare() |
原因は、doInBackground() 内で UI に関する処理を行なっていたためでした。
(具体的には、エラーメッセージを Toast で表示しようとしていた)
エラーが発生したときは、doInBackground() 内でエラーダイアログの表示などは行わず return null を返して、 onPostExecute メソッド内で良しなにエラー通知をするべきです。
メソッドdoInBackgroundはUIスレッドとは別なプールから取得されたスレッド上で実行されるのでGUI操作をしてはならない。代わりにUTスレッドと同期されるonProgressUpdateやonPostExecuteメソッド内でGUI操作を完了できる。
[参考]
・Android Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow
・android – Can't create handler inside thread that has not called Looper.prepare() – Stack Overflow
Android アプリに、リアルタイムでクラッシュレポートを自動送信するサービスやツールをまとめてみました。
Crittercism
・Crittercism | Mobile Application Performance Management
・スマートフォンアプリのクラッシュログ解析サービス (crittercism と bugsense) を使ってみた – むらかみの雑記帳
BugSense
・超簡単!BugSenseでスマホアプリ/サイトのクラッシュ統計をとろう | Developers.IO
ACRA (Application Crash Report for Android)
・Android ACRAを使ってアプリのクラッシュ情報を自動送信する方法 | Tech Booster
以上です。