84

私のアプリには 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:/// でインテントを開始することは許可されていないようです。いくつかのグーグル検索の後、A File Provider を使用することをお勧めしました。

新しいコード:

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 を処理するアクティビティが見つかりません0x4000000 }

Android 7 (24) で APK ビューアーを開く方法はありますか?

4

5 に答える 5

179

多くの試行錯誤の後、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);
        }
    });
于 2016-10-19T12:17:27.877 に答える
17

start activity を呼び出すときにこの問題が発生しました。現在のアクティビティを一時停止した後、突然戻ってきて onResume を呼び出しました。何事もなかったかのように。私の問題は、マニフェストのこの許可にありました:

 <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

ほとんど誰もそれについて言及しませんでした。だからこれを覚えておいてください。sdk >= 24 では、file:/// で始まるインテントが必要なため、プロバイダーを使用する必要があります。sdk 24 の下では、content:/// で始まる uri を指定する必要があるため、sdk 24 以降ではファイル プロバイダーが必要です。@just_user が正解を書いているので、このコードを書く必要はないと思います。 https://stacklearn.ir

于 2019-08-14T09:06:13.943 に答える