[解決済み] Android Intent.VIEW_ACTIONを使用したapkのインストールがFile providerでうまくいかない。
質問
私のアプリには自動更新機能があり、APKをダウンロードし、ダウンロードが完了するとIntent.VIEW_ACTIONでアプリを開き、ユーザーにダウンロードしたAPKをインストールさせることができます。
Uri uri = Uri.parse("file://" + destination);
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setDataAndType(uri,
manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);
これはすべてのデバイスでうまく機能します < 24
Android 24 では、どうやら file:/// でインテントを開始することができなくなったようです。
新しいコードです。
Intent install = new Intent(Intent.ACTION_VIEW);
install.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri apkUri = FileProvider.getUriForFile(AutoUpdate.this,
BuildConfig.APPLICATION_ID + ".provider", file);
install.setDataAndType(apkUri,
manager.getMimeTypeForDownloadedFile(downloadId));
activity.startActivity(install);
今すぐ activity.startActivity(install); は、エラーをスローします。
Intent { act=android.intent.action.VIEW} を処理するアクティビティが見つかりませんでした。 dat=content://com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ=application/vnd.android.package-archive flg=0x4000000 }.
Android 7 (24)でAPKビューアを開く方法はありますか?
どのように解決するのですか?
Nougat より前の Android バージョンでインストール インテントを作成するために FileProvider を使用するとエラーが発生するため、いろいろ試した結果、Nougat より低いものに対して別のインテントを作成することで解決しました。
ActivityNotFoundException: No Activity found to handle Intent { act=android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }
Android Nougatで通常のUriを使用すると、以下のようなエラーが発生します。
FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()
エミュレータ上のAndroid NとAndroid Mを実行している携帯電話で動作している私のソリューションです。
File toInstall = new File(appDirectory, appName + ".apk");
Intent intent;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".fileprovider", toInstall);
intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData(apkUri);
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
Uri apkUri = Uri.fromFile(toInstall);
intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(apkUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
activity.startActivity(intent);
Android Nougat 7.1 に対応したアップデートを行いました。
また、マニフェストに REQUEST_INSTALL_PACKAGES というパーミッションを追加する必要があります。これは、Api Level 23 (Android 6.0 Marshmallow) から利用可能で、Level 25 (Android 7.1 Nougat) から必須となります。
UPDATEしてください。
インストールしようとするファイルが外部ストレージにある場合、外部ストレージへの読み込みと書き込みの権限を要求することを忘れないでください。また、Android Nougat以上の場合、正しいFileProviderを設定すること。
まず書き込み権限があるかどうかを
canReadWriteExternal()
を呼び出し、書き込み権限がない場合は
requestPermission()
を呼び出す前に
private static final int REQUEST_WRITE_PERMISSION = 786;
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
if (requestCode == REQUEST_WRITE_PERMISSION && grantResults[0] == PackageManager.PERMISSION_GRANTED)
Toast.makeText(this, "Permission granted", Toast.LENGTH_LONG).show();
}
private void requestPermission() {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M)
requestPermissions(new String[]{ Manifest.permission.WRITE_EXTERNAL_STORAGE}, REQUEST_WRITE_PERMISSION);
}
private boolean canReadWriteExternal() {
return Build.VERSION.SDK_INT < Build.VERSION_CODES.M ||
ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.WRITE_EXTERNAL_STORAGE) != PackageManager.PERMISSION_GRANTED;
}
外部ストレージのDownloadフォルダのファイルプロバイダの例です。 AndroidManifest.xml :
<application ... >
...
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="${applicationId}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
</application>
リソース/xml/filepaths.xml :
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path name="external_download" path="Download"/>
</paths>
.apk のインストール中に "パッケージの解析に問題があります." のようなエラーが発生した場合、読み取り/書き込みの許可を求めていないか、インストールしようとしたファイルが存在しないか壊れている可能性があります。
UPDATE FOR Android Oreo 8.0を公開しました。
Android Oreo 8.0以上では、現在のアプリケーションがAPKのインストールを許可されているかどうかを確認する必要があります。
自分のアプリがAPKのインストールを許可されているかどうかは canRequestPackageInstallsを使用します。 メソッドで確認できます。falseを返した場合、インテントを起動するために action_manage_unknown_app_sources アクションを使用してインテントを起動し、ユーザーがアプリに APK をインストールすることを許可できる設定ダイアログを表示します。
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O
&& !getPackageManager().canRequestPackageInstalls()) {
Intent unknownAppSourceIntent = new Intent()
.setAction(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES)
.setData(Uri.parse(String.format("package:%s", getPackageName())));
unknownAppSourceDialog.launch(unknownAppSourceIntent);
} else {
// App already have the permission to install so launch the APK installation.
startActivity(intent);
}
インテントの結果を受け取るために、以下のコードをアクティビティに追加していることを確認してください。
ActivityResultLauncher<Intent> unknownAppSourceDialog = registerForActivityResult(
new ActivityResultContracts.StartActivityForResult(),
result -> {
if (result.getResultCode() == Activity.RESULT_OK) {
// User has allowed app to install APKs
// so we can now launch APK installation.
startActivity(intent);
}
});
関連
-
[解決済み】Android 8:クリアテキストのHTTPトラフィックが許可されない
-
[解決済み] APKファイルからソースコードを取得する方法はありますか?
-
[解決済み] Wi-Fi経由でAndroidアプリケーションを実行/インストール/デバッグしますか?
-
[解決済み] AndroidエミュレーターにAPKファイルをインストールする方法を教えてください。
-
[解決済み] Androidのエラーです。デバイス*に*.apkをインストールできませんでした: タイムアウト
-
[解決済み] Android App Bundleを端末にインストールする
-
[解決済み] Eclipseでのandroid:configChangesでのAdmobエラー
-
[解決済み] handler.postDelayed()を停止する。
-
[解決済み] Android Studio - あいまいなメソッド呼び出し getClass()
-
[解決済み] Android - Snackbar vs Toast - 使い方と違い。
最新
-
nginxです。[emerg] 0.0.0.0:80 への bind() に失敗しました (98: アドレスは既に使用中です)
-
htmlページでギリシャ文字を使うには
-
ピュアhtml+cssでの要素読み込み効果
-
純粋なhtml + cssで五輪を実現するサンプルコード
-
ナビゲーションバー・ドロップダウンメニューのHTML+CSSサンプルコード
-
タイピング効果を実現するピュアhtml+css
-
htmlの選択ボックスのプレースホルダー作成に関する質問
-
html css3 伸縮しない 画像表示効果
-
トップナビゲーションバーメニュー作成用HTML+CSS
-
html+css 実装 サイバーパンク風ボタン
おすすめ
-
[解決済み] Android: プログラムで .apk をインストールする [重複].
-
[解決済み] プログラムでソフトキーボードを開く
-
[解決済み] AsyncTaskを複数回実行する
-
[解決済み] Studio 3.4 をアップデートしたら、引数の leftShift() メソッドが見つかりませんでした。
-
[解決済み] edittextのテキストがメールアドレスかどうかを確認するには?
-
[解決済み] BottomNavigationViewを新しいNavControllerで使用する際に、フラグメントを生かす方法はありますか?
-
[解決済み] Androidでツールバーの戻るボタンの色を変えるには?
-
[解決済み] google-services.jsonって実際何してるの?
-
[解決済み] Android: xml リソースからの整数値
-
[解決済み] Travis.yml ./gradlew : パーミッションが拒否されました。