カテゴリー : Android

[Android] アプリデザインの参考情報まとめ

Android アプリデザインの参考情報まとめ、というかリンク集

Androidアプリデザインの基礎知識 | ジェネシックスブログ

Y.A.M の 雑記帳: Android UI Design Tips

[Android] OAuth2認証の実装方法

Androidアプリで、OAuth2認証を実装するときに参考になった情報をメモ。

scribe-javaを使う方法

fernandezpablo85/scribe-java

WebViewを使う方法

琴線探査: AndroidでGoogleのOAuth2認証を行うには?(外部ライブラリ完全非依存版)

AccountManagerを使う方法

琴線探査: AndroidのAccountManagerを使ったOAuth2認証は何だか怪しい

琴線探査: Androidのアカウントマネージャー経由のOAuth2は本当にユーザーフレンドリーなのか?

琴線探査: AndroidのAccountManager経由でGoogleのOAuth2認証を行うには?(外部ライブラリ完全非依存版)

AndroidとiPhoneで使えるURLスキーム起動&アプリ未ダウンロードならストアへリダイレクトするJavaScriptサンプルコード

Android と iPhone で使える URL スキーム起動&アプリ未ダウンロードならストアへリダイレクトするJavaScriptサンプルコードをご紹介します。

<!DOCTYPE html>
<html lang="ja">
  <head>
    <meta charset="utf-8">
    <title>URL scheme / Redirect Test</title>
 
    <script type="text/javascript">
    var userAgent = navigator.userAgent.toLowerCase();
 
    window.onload = function(){
 
      if (userAgent.indexOf("android") > -1) {
        // Launch myapp via URL scheme
        launch_frame.location.href= "myapp://";
 
        setTimeout(function(){
          // Open App DL page in Google Play
          location.href= "http://market.android.com/details?id=com.example.myapp";
        } , 500);
      } else if (userAgent.search(/iphone|ipad|ipod/) > -1) {
        // Launch myapp via URL scheme
        launch_frame.location.href= "myapp://";
 
        setTimeout(function(){
          // Open App DL page in iTunes Store
          location.href= "itmss://itunes.apple.com/us/app/myapp/id123456789?ls=1&mt=8";
        } , 500);
      }
 
    }
    </script>
 
  </head>
 
<body>
  <div style="width:0; height:0; overflow:hidden;">
  <iframe id="launch_frame" name="launch_frame">
  </iframe>
  </div>
</body>
 
</html>

[Android] Application#onCreate は Activity, Service, Receiver オブジェクトが生成される前に呼び出される

Android アプリ開発にて、Application#onCreate は Activity, Service, Receiver オブジェクトが生成される前に呼び出されるみたいです。

public void onCreate ()

Called when the application is starting, before any activity, service, or receiver objects (excluding content providers) have been created.
Implementations should be as quick as possible (for example using lazy initialization of state) since the time spent in this function directly impacts the performance of starting the first activity, service, or receiver in a process. If you override this method, be sure to call super.onCreate().

[引用元]:Application#onCreate() | Android Developers

例えば、Application#onCreate メソッド内に Google Analytics のアクセス解析処理を書いてたりすると、Service や Receiver オブジェクトが生成される度にトラッキングされてしまいます。

このせいで、アクティブユーザ数やセッション数が異常値になってしまったりするので注意が必要です。

[Android] Google Play で「お使いの端末はこのバージョンに対応していません。」と表示される場合にチェックすべき点

開発した Android アプリが、Google Play で「お使いの端末はこのバージョンに対応していません。」と表示される場合にチェックすべきポイントをメモ。

「お使いの端末はこのバージョンに対応していません。」発生時のチェック項目

下記に、Androidでインストール可能な端末を限定する方法が書かれているので、ここに該当してる項目がないかチェックしましょう。

Android Tips #18 インストール可能な端末を限定する | Developers.IO

カメラ機能を使ったアプリで除外端末になってしまう例

例えば、カメラ機能をマニフェストで要求している場合、カメラを搭載していないAndroid端末は除外対象になってしまいます。

そういう場合は、uses-feature で android:required=”false” を記述する必要があります。

●<uses-permission>を記載して<uses-feature>を記載しなかった場合、自動的に有効になる<uses-feature>がある。

android.permission.CAMERAの例にとると<uses-feature>の記載がなくても以下の機能が有効になります。

<uses-feature android:name="android.hardware.camera" android:required="true" />
<uses-feature android:name="android.hardware.camera.autofocus"android:required="true" />

どのパーミッションでどの機能が自動的に有効になるかは以下サイトを参考にしてみてください。
http://developer.android.com/guide/topics/manifest/uses-feature-element.html#permissions

まとめ

カメラや位置情報を使ったアプリだと除外端末が増えてしまうので、しっかり <uses-feature> を確認する必要がありそうですね。

<uses-feature> | Android Developers

必須機能では無い場合、 android:required=”false” を指定して、インストール可能端末を増やして、インストールの機会損失を減らすように心掛けたいものです。

参考情報

Nexus7・N-06D・P-08DにおいてGoogle Playから「端末仕様確認ツール」がダウンロードできない事象について – NTTドコモ開発者情報Blog

[Android] Nexus7で「開発者向けオプション」を表示して「USBデバッグ」を有効にする方法

Nexus7(ネクサスセブン)で「開発者向けオプション」を表示して「USBデバッグ」を有効にする方法をご紹介します。


「開発者向けオプション」の表示方法

[設定] > [タブレット情報] の「ビルド番号」という項目を7回タップします。

そうすると、設定に「開発者向けオプション」という項目が表示されます。


「USBデバッグ」を有効にする

[設定] > [{ }開発者向けオプション] にて、「USBデバッグ」のチェックボックスにチェックを入れます。

以上です。

[Android] FILL_PARENT は非推奨(deprecated)なので MATCH_PARENT を使う(Android2.2以降)

Android アプリ開発にて、2.2以降 は FILL_PARENT は非推奨(deprecated)なので MATCH_PARENT を使うべきだそうです。

ただ、名前変更だけのリファクタリングらしいですが。

[参考]

Yukiの枝折: Android:match_parentとfill_parent

[Android] Crittercism でリアルタイムにクラッシュレポートを把握する

Android アプリに、リアルタイムにクラッシュレポートを把握できる「Crittercism」というサービスを導入しました。

Crittercism | Mobile Application Performance Management

無料版でも、充分使えてかなり助かってます。

今回は、公式ドキュメントに書かれている内容に自分で調べたメモを追加しました。

Crittercism – Installation Instructions

以下、実際に使ってるコードをメモ。

AndroidManifest.xml

<uses-permission android:name="android.permission.INTERNET"/>

READ_LOGS パーミッションについては、ユーザの半分以上が Android 4.1 以上の端末を使っていたので、付与しませんでした。

Android 4.1 以上での動作について Android 4.1 (Jelly Bean) 以上の端末では、この設定を行わなくてもリモート LogCat は機能します。一方、セキュリティ上の理由から、アプリ自身のプロセスから出力されたログ以外は、参照することができません。

[引用]:リモートLogCatの有効化 – DeployGate

MainActivity.java

initCrittercism メソッドは、onCreate メソッドから呼び出します。

import com.crittercism.app.Crittercism;
 
/**
 * Initialize Crittercism (Error reporting and monitoring tool.)
 * http://www.crittercism.com
 */
private void initCrittercism() {
    JSONObject crittercismConfig = new JSONObject();
    try {
        // include version code in version name
        crittercismConfig.put("includeVersionCode", true);
        // necessary for collecting logcat data on Android Jelly Bean devices.
        crittercismConfig.put("shouldCollectLogcat", true);
    } catch (JSONException je) {
    }
 
    Crittercism.init(getApplicationContext(), "<CRITTERCISM_APP_ID>", crittercismConfig);
}

proguard.cfg

proguard を使う場合は、下記の設定も追加しておきましょう。

-keep public class com.crittercism.**
 
-keepclassmembers public class com.crittercism.*
{
    *;
}

最後に、READ_LOGS パーミッションについてよく分からなくて、サポートに問い合わせた時の返信内容をメモ。

Hey,

I’ll try to give you a brief tour of this permission and how it interacts with Crittercism.

Crittercism does not require the READ_LOGS permission in order to function correctly. However, by enabling this permission (where applicable), it can provide additional useful information with every crash and exception report that Crittercism receives.

The Android API:

The logs permission functions in two very different ways depending on the version of the Android API. For versions 15 and lower, any access to the logs requires this permission, and its inclusion gives complete access to all log entries.

As you mentioned, such a global permission poses a potential security risk, and at the very least raises questions about data separation. For this reason, starting in Jelly Bean (API version 16 and higher), Google changed its policy about log access.

After the policy change READ_LOGS no longer works for API Level 16 and higher. With these versions, each app has access to log entries generated by the app itself.

To enable logcat collection for newer devices, you need to include the following code in the onCreate() method of your main activity:

// create the JSONObject. (Do not forget to import org.json.JSONObject!) 
JSONObject crittercismConfig = new JSONObject(); 
try 
{ 
crittercismConfig.put("shouldCollectLogcat", true); // send logcat data for devices with API Level 16 and higher 
} 
catch (JSONException je){}
 
Crittercism.init(getApplicationContext(), "<CRITTERCISM_APP_ID>", crittercismConfig);

Does that answer your questions? For further details, please refer to our documentation, here https://app.crittercism.com/developers/docs-android#including_logcat .

Best regards,

以上です。

[Android] Google Analytics の使い方の参考情報

Android アプリで、Google Analytics を使うために参考にした情報をまとめました。

Google Analytics 公式ドキュメント

Google Analytics SDK for Android v2 (Beta) – Overview

Google Play のダウンロードがどこ経由かトラッキングするためのキャンペーンのパラメータ付きURLを簡単に生成できるツール
Campaign Measurement – Android SDK – Google Analytics

チームEGGによる翻訳ドキュメント

① 「概要」
②「高度な設定」
③「キャンペーントラッキング」
④「クラッシュと例外」
⑤「ディスパッチング」
⑥「eコマーストラッキング」
⑦「イベント」
⑧「スクリーン」
⑨「セッション」
⑩「ユーザータイミング」
⑪「EasyTrackerパラメータ」

[Android] IllegalStateException: Cannot add header view to list : setAdapter has already been called.

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