Frage

Ich habe Interesse zu wissen, ob es möglich ist, programmatisch eine dynamisch heruntergeladen apk aus einer benutzerdefinierten Android-Anwendung installiert werden.

War es hilfreich?

Lösung

Sie können ganz einfach ein Spiel Speicherverbindung starten oder installieren Aufforderung:

Intent promptInstall = new Intent(Intent.ACTION_VIEW)
    .setDataAndType(Uri.parse("content:///path/to/your.apk"), 
                    "application/vnd.android.package-archive");
startActivity(promptInstall); 

oder

Intent goToMarket = new Intent(Intent.ACTION_VIEW)
    .setData(Uri.parse("https://play.google.com/store/apps/details?id=com.package.name"));
startActivity(goToMarket);

Sie können jedoch nicht .apks installieren, ohne dass der Benutzer ausdrückliche Erlaubnis ; es sei denn, das Gerät und Ihr Programm verwurzelt ist.

Andere Tipps

File file = new File(dir, "App.apk");
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);

Ich hatte das gleiche Problem und nach mehreren Versuchen war es auf diese Weise für mich aus. Ich weiß nicht, warum, aber Einstelldaten und Typ separat meine Absicht vermasselt.

Die Lösungen auf diese Frage sind alle für targetSdkVersion s von 23 und darunter. Für Android N, das heißt API-Ebene 24, und oben, jedoch tun sie nicht arbeiten und Absturz mit folgenden Ausnahme:

android.os.FileUriExposedException: file:///storage/emulated/0/... exposed beyond app through Intent.getData()

Das ist aufgrund der Tatsache, dass Android ab 24, die Uri die heruntergeladene Datei zur Adressierung geändert hat. Zum Beispiel würde eine Installationsdatei mit dem Namen appName.apk auf dem primären externe Dateisystem des App mit Paketnamen com.example.test gespeichert sein, wie

file:///storage/emulated/0/Android/data/com.example.test/files/appName.apk

für API 23 und unten, während so etwas wie

content://com.example.test.authorityStr/pathName/Android/data/com.example.test/files/appName.apk

für API 24 und oben.

Weitere Details hierzu finden sich und ich bin nicht dabei, es zu gehen.

Um die Frage zu targetSdkVersion von 24 zu beantworten und oben, hat man die folgenden Schritte ausführen: Fügen Sie die folgende auf die AndroidManifest.xml:

<application
        android:allowBackup="true"
        android:label="@string/app_name">
        <provider
            android:name="android.support.v4.content.FileProvider"
            android:authorities="${applicationId}.authorityStr"
            android:exported="false"
            android:grantUriPermissions="true">
            <meta-data
                android:name="android.support.FILE_PROVIDER_PATHS"
                android:resource="@xml/paths"/>
        </provider>
</application>

2. Fügen Sie die folgende paths.xml-Datei in den Ordner xml auf res in src, Haupt:

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="pathName"
        path="pathValue"/>
</paths>

Die pathName ist, dass in dem beispielhaften Inhalt uri Beispiel oben gezeigt und pathValue der tatsächliche Weg auf dem System befindet. Es wäre eine gute Idee, ein setzen „“ (Ohne Anführungszeichen) für Pfadwert in diesem Befehl, wenn Sie nicht wollen, kein zusätzliches Unterverzeichnis hinzuzufügen.

  1. Schreiben Sie den folgenden Code, um die apk mit dem Namen appName.apk auf dem primären externen Dateisystem zu installieren:

    File directory = context.getExternalFilesDir(null);
    File file = new File(directory, fileName);
    Uri fileUri = Uri.fromFile(file);
    if (Build.VERSION.SDK_INT >= 24) {
        fileUri = FileProvider.getUriForFile(context, context.getPackageName(),
                file);
    }
    Intent intent = new Intent(Intent.ACTION_VIEW, fileUri);
    intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
    intent.setDataAndType(fileUri, "application/vnd.android" + ".package-archive");
    intent.setFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
    intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
    context.startActivity(intent);
    activity.finish();
    

Keine Erlaubnis ist auch notwendig, wenn zu Ihrer eigenen App privaten Verzeichnis auf dem externen Dateisystem zu schreiben.

Ich habe eine Autoupdate-Bibliothek geschrieben hier , in dem ich die oben verwendet haben.

Nun, digged ich tiefer und fand Quellen PackageInstaller Anwendung von Android Quelle.

https://github.com/android/platform_packages_apps_packageinstaller

Von Manifest fand ich, dass es benötigt eine gesonderte Genehmigung:

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

Und der eigentliche Prozess der Installation erfolgt nach Bestätigung

Intent newIntent = new Intent();
newIntent.putExtra(PackageUtil.INTENT_ATTR_APPLICATION_INFO, mPkgInfo.applicationInfo);
newIntent.setData(mPackageURI);
newIntent.setClass(this, InstallAppProgress.class);
String installerPackageName = getIntent().getStringExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME);
if (installerPackageName != null) {
   newIntent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, installerPackageName);
}
startActivity(newIntent);

Ich möchte nur die Tatsache teilen, dass meine apk-Datei zu meiner App „Data“ Verzeichnis gespeichert wurde und dass ich brauchte, um die Berechtigungen für die APK-Datei zu ändern Welt lesbar sein, um es zu ermöglichen, installiert wird auf dieser Weise, ansonsten wurde das System „Parse error: Es gibt ein Problem beim Analysieren der Package“ zu werfen; so unter Verwendung einer Lösung von @Horaceman dass Marken:

File file = new File(dir, "App.apk");
file.setReadable(true, false);
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
startActivity(intent);

Ein andere Lösung, die hart Code nicht nicht den Empfang App erfordert, und das ist daher sicherer:

Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
intent.setData( Uri.fromFile(new File(pathToApk)) );
startActivity(intent);

Ja, es ist möglich. Aber, dass Sie das Telefon benötigen nicht verifizierten Quellen zu installieren. Zum Beispiel macht SlideME dass. Ich denke, das Beste, was Sie tun können, ist zu prüfen, ob die Anwendung vorhanden ist, und eine Absichtserklärung für den Android Market senden. Sie sollten etwas das URL-Schema für Android Market verwenden.

market://details?id=package.name

Ich weiß nicht genau, wie die Aktivität zu starten, aber wenn Sie eine Aktivität mit dieser Art von URL starten. Es sollte den Android-Markt öffnen und gibt Ihnen die Wahl, um die Anwendungen zu installieren.

Es ist erwähnenswert, dass, wenn Sie die DownloadManager zu Kick-off des Download verwenden, sollten Sie es an einen externen Speicherort speichern z.B. setDestinationInExternalFilesDir(c, null, "<your name here>).apk";. Die Absicht mit einem Paket-Archivtyp erscheint nicht das content: Schema mit Downloads auf eine interne Stelle verwendet zu mögen, aber tut wie file:. (Der Versuch, den inneren Weg in ein File-Objekt zu wickeln und dann den Pfad immer entweder nicht funktioniert, obwohl es in einem file: URL führt, da die App nicht die apk analysiert, sieht aus wie es extern sein muss.)

Beispiel:

int uriIndex = cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI);
String downloadedPackageUriString = cursor.getString(uriIndex);
File mFile = new File(Uri.parse(downloadedPackageUriString).getPath());
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
        .setDataAndType(Uri.fromFile(mFile), "application/vnd.android.package-archive")
        .addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
appContext.startActivity(promptInstall);

Auf diese Weise können andere viel!

Erstens:

private static final String APP_DIR = Environment.getExternalStorageDirectory().getAbsolutePath() + "/MyAppFolderInStorage/";

private void install() {
    File file = new File(APP_DIR + fileName);

    if (file.exists()) {
        Intent intent = new Intent(Intent.ACTION_VIEW);
        String type = "application/vnd.android.package-archive";

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
            Uri downloadedApk = FileProvider.getUriForFile(getContext(), "ir.greencode", file);
            intent.setDataAndType(downloadedApk, type);
            intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
        } else {
            intent.setDataAndType(Uri.fromFile(file), type);
            intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        }

        getContext().startActivity(intent);
    } else {
        Toast.makeText(getContext(), "ّFile not found!", Toast.LENGTH_SHORT).show();
    }
}

Zweitens: für Android 7 und höher Sie einen Anbieter in manifest wie unten definieren sollten

    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="ir.greencode"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/paths" />
    </provider>

Drittens: definieren path.xml in res / xml-Ordner wie unten! Ich verwende diesen Pfad für interne Speicher, wenn Sie wollen, es zu etwas ändern, sonst gibt es ein paar Weg! Sie können auf diesen Link gehen: FileProvider

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path name="your_folder_name" path="MyAppFolderInStorage/"/>
</paths>

Forth: Sie sollten diese Erlaubnis in Manifest hinzufügen:

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

Bitte stellen Sie sicher, dass die Anbieter Behörden gleich sind!


nur eine Erweiterung, wenn jemand Bedarf eine Bibliothek dann diese helfen könnte. Dank Raghav

Versuchen Sie, diese

String filePath = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
String title = filePath.substring( filePath.lastIndexOf('/')+1, filePath.length() );
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(filePath)), "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); // without this flag android returned a intent error!
MainActivity.this.startActivity(intent);

UpdateNode bietet eine API für Android APK-Pakete von innerhalb einer anderen App zu installieren.
Sie können Ihre Update-online und integrieren die API in Ihre App nur definieren - das es ist.
Derzeit ist die API im Beta-Stadium, aber Sie können bereits einige Tests selbst tun.
Außer, dass auch UpdateNode Angebote Nachrichten obwohl das System die Anzeige - ziemlich nützlich, wenn Sie etwas Wichtiges zu Ihren Benutzern sagen wollen.
Ich bin ein Teil des Client-Entwickler-Team und bin mit zumindest die Nachricht Funktionalität für meine eigene Android App.

Sehen Sie hier eine Beschreibung, wie die API

integrieren

Zuerst die folgende Zeile AndroidManifest.xml hinzufügen:

<uses-permission android:name="android.permission.INSTALL_PACKAGES"
    tools:ignore="ProtectedPermissions" />

Sie dann den folgenden Code verwenden, installieren apk:

File sdCard = Environment.getExternalStorageDirectory();
            String fileStr = sdCard.getAbsolutePath() + "/MyApp";// + "app-release.apk";
            File file = new File(fileStr, "TaghvimShamsi.apk");
            Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.fromFile(file),
                    "application/vnd.android.package-archive");
            startActivity(promptInstall);

Vergessen Sie nicht, auf Anfrage Berechtigungen:

android.Manifest.permission.WRITE_EXTERNAL_STORAGE 
android.Manifest.permission.READ_EXTERNAL_STORAGE

Fügen Sie in AndroidManifest.xml die Anbieter und die Erlaubnis:

<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
...
<application>
    ...
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="${applicationId}"
        android:exported="false"
        android:grantUriPermissions="true">
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/provider_paths"/>
    </provider>
</application>

Erstellen von XML-Datei Anbieter res / xml / provider_paths.xml

<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
    <external-path
        name="external"
        path="." />
    <external-files-path
        name="external_files"
        path="." />
    <cache-path
        name="cache"
        path="." />
    <external-cache-path
        name="external_cache"
        path="." />
    <files-path
        name="files"
        path="." />
</paths>

Verwenden Sie den folgenden Beispielcode:

   public class InstallManagerApk extends AppCompatActivity {

    static final String NAME_APK_FILE = "some.apk";
    public static final int REQUEST_INSTALL = 0;

     @Override
    protected void onCreate(@Nullable Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);

        // required permission:
        // android.Manifest.permission.WRITE_EXTERNAL_STORAGE 
        // android.Manifest.permission.READ_EXTERNAL_STORAGE

        installApk();

    }

    ...

    /**
     * Install APK File
     */
    private void installApk() {

        try {

            File filePath = Environment.getExternalStorageDirectory();// path to file apk
            File file = new File(filePath, LoadManagerApkFile.NAME_APK_FILE);

            Uri uri = getApkUri( file.getPath() ); // get Uri for  each SDK Android

            Intent intent = new Intent(Intent.ACTION_INSTALL_PACKAGE);
            intent.setData( uri );
            intent.setFlags( Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_ACTIVITY_NEW_TASK );
            intent.putExtra(Intent.EXTRA_NOT_UNKNOWN_SOURCE, true);
            intent.putExtra(Intent.EXTRA_RETURN_RESULT, true);
            intent.putExtra(Intent.EXTRA_INSTALLER_PACKAGE_NAME, getApplicationInfo().packageName);

            if ( getPackageManager().queryIntentActivities(intent, 0 ) != null ) {// checked on start Activity

                startActivityForResult(intent, REQUEST_INSTALL);

            } else {
                throw new Exception("don`t start Activity.");
            }

        } catch ( Exception e ) {

            Log.i(TAG + ":InstallApk", "Failed installl APK file", e);
            Toast.makeText(getApplicationContext(), e.getMessage(), Toast.LENGTH_LONG)
                .show();

        }

    }

    /**
     * Returns a Uri pointing to the APK to install.
     */
    private Uri getApkUri(String path) {

        // Before N, a MODE_WORLD_READABLE file could be passed via the ACTION_INSTALL_PACKAGE
        // Intent. Since N, MODE_WORLD_READABLE files are forbidden, and a FileProvider is
        // recommended.
        boolean useFileProvider = Build.VERSION.SDK_INT >= Build.VERSION_CODES.N;

        String tempFilename = "tmp.apk";
        byte[] buffer = new byte[16384];
        int fileMode = useFileProvider ? Context.MODE_PRIVATE : Context.MODE_WORLD_READABLE;
        try (InputStream is = new FileInputStream(new File(path));
             FileOutputStream fout = openFileOutput(tempFilename, fileMode)) {

            int n;
            while ((n = is.read(buffer)) >= 0) {
                fout.write(buffer, 0, n);
            }

        } catch (IOException e) {
            Log.i(TAG + ":getApkUri", "Failed to write temporary APK file", e);
        }

        if (useFileProvider) {

            File toInstall = new File(this.getFilesDir(), tempFilename);
            return FileProvider.getUriForFile(this,  BuildConfig.APPLICATION_ID, toInstall);

        } else {

            return Uri.fromFile(getFileStreamPath(tempFilename));

        }

    }

    /**
     * Listener event on installation APK file
     */
    @Override
    protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) {
        super.onActivityResult(requestCode, resultCode, data);

        if(requestCode == REQUEST_INSTALL) {

            if (resultCode == Activity.RESULT_OK) {
                Toast.makeText(this,"Install succeeded!", Toast.LENGTH_SHORT).show();
            } else if (resultCode == Activity.RESULT_CANCELED) {
                Toast.makeText(this,"Install canceled!", Toast.LENGTH_SHORT).show();
            } else {
                Toast.makeText(this,"Install Failed!", Toast.LENGTH_SHORT).show();
            }

        }

    }

    ...

}

Versuchen Sie, diese - Schreiben Sie auf Manifest:

uses-permission android:name="android.permission.INSTALL_PACKAGES"
        tools:ignore="ProtectedPermissions"

Schreiben Sie den Code:

File sdCard = Environment.getExternalStorageDirectory();
String fileStr = sdCard.getAbsolutePath() + "/Download";// + "app-release.apk";
File file = new File(fileStr, "app-release.apk");
Intent promptInstall = new Intent(Intent.ACTION_VIEW).setDataAndType(Uri.fromFile(file),
                        "application/vnd.android.package-archive");

startActivity(promptInstall);
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top