Android

Android でアプリから URL を強制的にブラウザで開く

More than 1 year has passed since last update.

通常の方法

アプリから URL をブラウザで開く場合、基本的には以下の様なインテントを投げ、システムに解決してもらう。

Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
startActivity(intent);

ただしこの方法では強制的に URL をブラウザで開くことはできない。特にアプリ自身がそのURLを受け取れる場合、再びアプリに戻ってきてしまったり、ブラウザの選択画面に再びアプリが出てきてしまう。そのためアプリで表示しているページをブラウザで開く機能や、アプリではサポートしていないページをウェブにフォールバックさせるためには以下のような工夫が必要となる。

デフォルトブラウザで開く

デフォルトのアプリは PackageManager.resolveActivity で取得できる。"https://" に対するデフォルトのアプリを取得することで、デフォルトアプリのパッケージ名を得ることができる。

// "https://" をハンドルするデフォルトアプリを取得する
Intent browser = new Intent(Intent.ACTION_VIEW, Uri.parse("https://"));
ResolveInfo defaultResInfo = 
    getPackageManager().resolveActivity(browser, PackageManager.MATCH_DEFAULT_ONLY);
if (defaultResInfo != null) {
    Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
    intent.setPackage(defaultResInfo.activityInfo.packageName);
    try {
        startActivity(intent);
        return;
    } catch (ActivityNotFoundException e) {
        // resolveActivity はデフフォルトアプリが設定されていない場合、
        // activity resolver などが含まれる ResolveInfo を返しうる。
    }
}

ブラウザを選ばせる

ユーザーがデフォルトブラウザを設定していない場合はアプリを選ばせる必要がある。ここではアプリからブラウザへ遷移することを想定しているので、アプリ自体は選択画面から消したい。PackageManager.queryIntentActivitiesを使ってアプリ一覧を取得し、それぞれのアプリを開くインテントをIntent.EXTRA_INITIAL_INTENTSに渡して、明示的に開くアプリを指定することで、アプリが選択画面に現れることを回避できる。

// url をハンドルできるパッケージを取得する
Intent intent = new Intent(Intent.ACTION_VIEW, Uri.parse(url));
List<ResolveInfo> resInfos = getPackageManager().queryIntentActivities(intent, PackageManager.MATCH_DEFAULT_ONLY);
List<Intent> intents = new ArrayList<>();
for (ResolveInfo resInfo : resInfos) {
    Intent targeted = new Intent(intent);
    String packageName = resInfo.activityInfo.packageName;
    // 自分のアプリを選択から外す。
    if (getPackageName().equals(packageName)) {
        continue;
    }
    targeted.setPackage(packageName);
    intents.add(targeted);
}
// アプリリストは明示的に EXTRA_INITIAL_INTENTS で指定しているので、
// createChooser には空の Intent を渡す。
Intent chooser = Intent.createChooser(new Intent(), "ブラウザで開く");
chooser.putExtra(Intent.EXTRA_INITIAL_INTENTS, intents.toArray(new Parcelable[0]));
startActivity(chooser);

環境

Android 7.0 がインストールされた Nexus 5x 上でのみ確認。

参考:
http://stackoverflow.com/questions/8626421/get-preferred-default-app-on-android
http://stackoverflow.com/questions/35501671/force-to-open-link-in-browser-for-fallback
http://meta.stackexchange.com/questions/259635/what-android-intent-does-se-apps-open-in-browser-use?rq=1