多くの試行錯誤の後、Nougat がエラーを引き起こす前に、FileProvider を使用して Android バージョンでインストール インテントを作成するため、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 レベル 23 (Android 6.0 Marshmallow) から利用でき、レベル 25 (Android 7.1 Nougat) から必須です。
アップデート:
インストールしようとしているファイルが外部ストレージにある場合は、外部ストレージへの読み取りと書き込みのアクセス許可を要求することを忘れないでください。また、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;
}
以下は、外部ストレージのダウンロード フォルダーのファイル プロバイダーの例です。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>
resources/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 のインストール中に「パッケージの解析中に問題が発生しました」などのエラーが発生した場合。読み取り/書き込み許可を要求していないか、インストールしようとしているファイルが存在しないか破損している可能性があります。
Android Oreo 8.0 の更新:
現在のアプリケーションが Android Oreo 8.0 以降に APK をインストールできるかどうかを確認する必要があります。
PackageManager クラスのcanRequestPackageInstallsメソッドを使用して、アプリが APK のインストールを許可されているかどうかを確認できます。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);
}
});