Android: PackageManager: apkの壁を超えてclassの存在確認をする

初稿2010/9
#はじめに
apk内に閉じてclassの存在を確認するならClass.forName()でOKですが、他のapk内にあるclassの確認はできません
PackageManagerのgetActivityInfoを使います

- apk内ならClass.forNameしてClassNotFoundExceptionを拾う

```
try {
 Class.forName("jp.co.na.Entry");
} catch (ClassNotFoundException e) {
 Log.d(TAG,  "class Not exists.");
}
```

- 別のapkの場合はPackageManagerのgetActivityInfoしてNameNotFoundExceptionを拾う

```
PackageManager mManager = getPackageManager();
try {
  mManager.getActivityInfo(new ComponentName("jp.co.na", "jp.co.na.Entry"), 0);
} catch (NameNotFoundException e) {
  Log.d(TAG, "class Not exists.");
}
```

これを使って、Entryという名前のActivityが複数のapkに存在して、順番に存在確認をして一番最初に見つかったpackageに画面遷移するコードは以下のような感じ

```

//apkを跨ってclassを探すときは、PackageManagerさんに聞く
package jp.co.na.main;

public class mainAct extends Activity {
  static final String TAG = "mainAct";

  PackageManager mManager = null;
  String next_page = ".Entry";	// 遷移先Activityのクラス名

  /** Called when the activity is first created. */
  @Override
  public void onCreate(Bundle savedInstanceState) {
      super.onCreate(savedInstanceState);
      setContentView(R.layout.main);
      Button b = (Button)findViewById(R.id.Button01);
      b.setOnClickListener(mButtonListener);

      mManager = getPackageManager();
  }

 private View.OnClickListener mButtonListener =
 new View.OnClickListener() {
    public void onClick(View v) {

    // 遷移先Activityがどの(apkを跨った)パッケージに含まれるか探す
    try {
      // apk1をチェック
      String package_name = "jp.co.na.a.b.c";
      String class_name = package_name + next_page;
      mManager.getActivityInfo(new ComponentName(package_name, class_name), 0);
    } catch (NameNotFoundException e) {
      Log.d(TAG, class_name + " Not exists.");
      try {
        // apk2をチェック
        String package_name = "jp.co.photo";
        String class_name = package_name + next_page;
        mManager.getActivityInfo(new ComponentName(package_name, class_name), 0);
        } catch (NameNotFoundException ee) {
          Log.d(TAG, class_name + " Not exists.");
          try {
            // apk3をチェック
            String package_name = "jp.co.zaku.model";
            String class_name = package_name + next_page;
            mManager.getActivityInfo(new ComponentName(package_name, class_name), 0);
          } catch (NameNotFoundException eee) {
            Log.d(TAG, class_name + " Not exists.");
            try {
              // 共通apkをチェック
              String package_name = "com.na.common";
              String class_name = package_name + next_page;
              mManager.getActivityInfo(new ComponentName(package_name, class_name), 0);
            } catch (NameNotFoundException eeee) {
              // どこにも無かったのでエラー
              Log.d(TAG, class_name + " Not exists.");
              eeee.printStackTrace();
            }
          }
        }
      }
      // 遷移先のActivityを指定して遷移
      Intent intent = new Intent();
      intent.setClassName(package_name, class_name);
      startActivity(intent);
    }
  };
}
```
実行ログ：どのpackageにもclassが無かった場合

```
D/a01     ( 1391): jp.co.na.a.b.c Not exists.       <--apk1をチェックして、無かった
D/a01     ( 1391): jp.co.photo Not exists.          <--apk2をチェックして、無かった
D/a01     ( 1391): jp.co.zaku.model Not exists.     <--apk3をチェックして、無かった
D/a01     ( 1391): com.na.common Not exists.        <--共通apkをチェックして、無かった
W/System.err( 1391): android.content.pm.PackageManager$NameNotFoundException: ComponentInfo{com.na.common/com.na.common.Entry}
W/System.err( 1391):    at android.app.ApplicationContext$ApplicationPackageManager.getActivityInfo(ApplicationContext.java:1619)
W/System.err( 1391):    at jp.co.na.main.mainAct$1.onClick(mainAct.java:54)
```