wake-up-neo.com

Android install apk mit Intent.VIEW_ACTION funktioniert nicht mit dem Dateianbieter

Meine App verfügt über eine Auto-Update-Funktion, mit der ein APK heruntergeladen wird. Wenn der Download abgeschlossen ist, kann Intent.VIEW_ACTION die App öffnen und den Benutzer die heruntergeladene APK installieren lassen

         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);

Dies funktioniert gut für alle Geräte <24

Jetzt mit Android 24 ist es anscheinend nicht mehr erlaubt, Absichten mit file: /// zu beginnen, und nach einigem Googlen wurde empfohlen, A File Provider zu verwenden

neuer Code:

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);

Nun Activity.startActivity (installieren); wirft einen Fehler

Es wurde keine Aktivität gefunden, um mit Intent umzugehen {act = Android.intent.action.VIEW dat = Inhalt: //com.xxxx.xx.provider/MyFolder/Download/MyApkFile.apk typ = application/vnd.Android.package-archive flg = 0x4000000}

Gibt es eine Möglichkeit, den APK-Viewer in Android 7 (24) zu öffnen?

42
Johny19

Nach langem Ausprobieren konnte ich dieses Problem lösen, indem ich verschiedene Intents für etwas niedrigeres als Nougat erstellte, als den FileProvider zum Erstellen einer Installationsabsicht mit Android-Versionen, bevor Nougat den Fehler verursacht:

ActivityNotFoundException: No Activity found to handle Intent { act=Android.intent.action.INSTALL_PACKAGE dat=content://XXX.apk flg=0x1 }

Bei Verwendung eines normalen Uri auf Android verursacht Nougat den folgenden Fehler:

FileUriExposedException: file:///XXX.apk exposed beyond app through Intent.getData()

Meine Lösung, die für mich mit Android N am Emulator und einem Telefon mit Android M arbeitet. 

File toInstall = new File(appDirectory, appName + ".apk");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    Uri apkUri = FileProvider.getUriForFile(activity, BuildConfig.APPLICATION_ID + ".provider", toInstall);
    Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
    intent.setData(apkUri);
    intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    activity.startActivity(intent)
} else {
    Uri apkUri = Uri.fromFile(toInstall);
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(apkUri, "application/vnd.Android.package-archive");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    activity.startActivity(intent);
}

AKTUALISIERUNG FÜR Android Nougat 7.1:

Sie müssen außerdem die Berechtigung REQUEST_INSTALL_PACKAGES in Ihrem Manifest hinzufügen. Es ist ab Api Level 23 (Android 6.0 Marshmallow) verfügbar und wird ab Level 25 (Android 7.1 Nougat) benötigt.

UPDATE:

Denken Sie daran, die Berechtigungen zum Lesen und Schreiben in den externen Speicher anzufordern, wenn sich die zu installierende Datei im externen Speicher befindet. Und auch einen korrekten FileProvider für Android Nougat und höher einrichten.

Prüfen Sie zunächst, ob Sie über eine Schreibberechtigung verfügen, indem Sie unten canReadWriteExternal() aufrufen, falls nicht zuvor requestPermission() aufgerufen wird:

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;
}

Hier ist ein Beispiel eines Dateiangebers für den Download-Ordner auf dem externen Speicher. 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>

Wenn Sie bei der Installation von .apk eine Fehlermeldung erhalten, die etwa Folgendes lautet: "Es gibt ein Problem beim Parsen des Pakets." Möglicherweise haben Sie nicht nach der Berechtigung zum Lesen/Schreiben gefragt, oder die zu installierende Datei existiert nicht oder ist beschädigt. 

99
just_user

Das könnte das Problem sein, das Sie haben

intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); 

in deinem Beispiel sollte es sein

install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);

wie install ist der Name der Absicht.

4
Rob Francis

Ich hatte dieses Problem, als ich start activity aufrief. Nachdem ich meine aktuelle Aktivität angehalten hatte, kam sie plötzlich zurück und rief onResume auf. als wäre nichts passiert. Mein Problem war mit dieser Erlaubnis in Manifest:

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

fast niemand erwähnte das. Also denk dran. in sdk> = 24 musst du provider verwenden, da es eine absicht braucht, die mit file: /// beginnt. unterhalb von sdk 24 solltest du uri mit content: /// beginnen, deshalb brauchen wir file provider für sdk 24 und höher. Ich glaube nicht, dass ich dafür irgendwelche Codes schreiben muss, da @just_user die richtige Antwort geschrieben hat.

1
Hossein Karami

Sie sollten beachten, dass Sie für API <24 Folgendes verwenden müssen:

        setDataAndType(Uri.fromFile(apkFile), "application/vnd.Android.package-archive")

anstatt Daten und Typ separat einzustellen:

data = Uri.fromFile(apkFile)
    type = "application/vnd.Android.package-archive"

andernfalls erhalten Sie ActivityNotFoundException

0
MohammadReza