【Android／Java】外部アプリ起動（Android11）

## やりたいこと
外部アプリを起動したい。
Android11から[package-visibility](https://developer.android.com/training/package-visibility/declaring?hl=ja)が導入され、外部アプリを起動するためのお作法が変更となった
とりあえず、起動させるためのお作法を記載

#### AndroidManifest.xml
~~~xml
<queries>
    <intent>
        <action android:name="android.intent.action.VIEW" />
        <data android:scheme="https" />
    </intent>
    <intent>
        <action android:name="android.intent.action.BROWSABLE" />
        <data android:scheme="https" />
    </intent>
    <intent>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LEANBACK_LAUNCHER" />
    </intent>
    <intent>
        <action android:name="android.intent.action.MAIN" />
        <category android:name="android.intent.category.LAUNCHER" />
    </intent>
</queries>
~~~

#### MainActivity.java
~~~java
String packageName = "hogehoge.co.jp";
String appUrl = "https://fugafuga.co.jp";

try {
    // パッケージ起動
    Intent intent = PackageManager.getLaunchIntentForPackage(packageName);
    context.startActivity(intent);
} catch (Exception e1) {
    try {
        // パッケージ起動
        Intent intent = PackageManager.getLeanbackLaunchIntentForPackage(packageName);
        context.startActivity(intent);
    } catch (Exception e2) {
        try {
            // URI起動
            Intent intent = new Intent(Intent.ACTION_VIEW);
            intent.setPackage(packageName);
            intent.setData(Uri.parse(appUrl));
            context.startActivity(intent);
        } catch (Exception e3) {
            Toast.makeText(context, "アプリを起動できません", Toast.LENGTH_SHORT).show();
        }
    }
}
~~~

### 解説
1. AndroidManifest.xml：外部アプリと連携するためのQueries定義。対象アプリによりけりだが、この辺りを設定すれば、ほぼ対応できていると思われる
1. MainActivity.java：getLaunchIntentForPackage()でスマホ向けアプリ起動を試みる、起動できない場合はExceptionga返却されるので次の起動をためす
getLeanbackLaunchIntentForPackage()でAndroidTV向けアプリの起動を試みる
最後に、URIスキーマでの起動を試みる

### URIスキーマの調べ方
最後の起動方法については、対象のアプリのAndroidManifest.xmlを参照する必要がある
1. インストールしている端末からAPKファイルの場所を特定する
adb shell pm list packages -f | findstr [パッケージ名]
→ package:<font color="red">/data/app/~~fugafugafugafuga==/[パッケージ名]-hogehogehogehogehoge==/base.apk</font>=[パッケージ名]
1. APKファイルをPCにおとす
adb pull <font color="red">/data/app/~~fugafugafugafuga==/[パッケージ名]-hogehogehogehogehoge==/base.apk</font>
1. APKを7Zipなどで解凍する
1. [AXMLPrinter2](https://github.com/digitalsleuth/AXMLPrinter2)でAndroidManifest.xmlを複合化する
java -jar AXMLPrinter2.jar AndroidManifest.xml > ConvertedManifest.xml
1. ConvertedManifest.xmlをテキストエディタで開いてスキームを確認（以下は、AmazonPrimeVideoの例）
#### ConvertedManifest.xml
~~~xml
<activity
    android:name="com.amazon.ignition.MainActivity"
    android:launchMode="2"
    android:screenOrientation="0"
    >
</activity>
    <intent-filter
        android:autoVerify="true"
        >
        <action
            android:name="android.intent.action.VIEW"
            >
        </action>
        <category
            android:name="android.intent.category.DEFAULT"
            >
        </category>
        <category
            android:name="android.intent.category.BROWSABLE"
            >
        </category>
        <data
            android:scheme="https"
            android:host="watch.amazon.com"
            >
        </data>
        <data
            android:scheme="http"
            android:host="watch.amazon.com"
            >
        </data>
~~~
上記の例の場合、URIで起動する場合は、"https://watch.amazon.com" を指定することで起動できる

### パラメータ渡し
Youtubeなどの例をあげると、Youtubeアプリを起動し、かつ、特定の動画を参照させたい場合があると思われる。
その場合、startActivityを行う前に、参照先のURLをintentに追加すれば解決できる

#### MainActivity.java
~~~java
try {
    // パッケージ起動
    Intent intent = PackageManager.getLaunchIntentForPackage(packageName);
    intent.setData(Uri.parse("https://xxxxx.yyyyyy"));
    context.startActivity(intent);
} catch (Exception e1) {
　　：
~~~

### 最後に
AndroidManifest.xmlのqueries定義の代わりに、QUERY_ALL_PACKAGES権限を付与することでもできるが、アプリを公開する場合に、いろいろと申請が必要になるらしい。
すなおにqueriesに定義を書いた方が良いと思われる。