wake-up-neo.com

Installieren Sie die Anwendung programmgesteuert auf Android

Ich bin daran interessiert zu wissen, ob es möglich ist, dynamisch heruntergeladene apk-Programme von einer benutzerdefinierten Android-Anwendung programmgesteuert zu installieren.

180
Alkersan

Sie können ganz einfach einen Marktlink oder eine Installationsaufforderung starten:

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

Quelle

Intent goToMarket = new Intent(Intent.ACTION_VIEW)
    .setData(Uri.parse("market://details?id=com.package.name"));
startActivity(goToMarket);

Quelle

Sie können jedoch keine .apks ohne explizite Berechtigung des Benutzers installieren. nicht, wenn das Gerät und Ihr Programm verwurzelt sind.

221
Lie Ryan
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 klappte es für mich so. Ich weiß nicht warum, aber die Einstellung von Daten und Typ hat meine Absichten in die Luft gejagt. 

54
Horaceman

Die Lösungen für diese Frage gelten alle für targetSdkVersion s von 23 und darunter. Für Android N, d. H. API-Stufe 24 und höher, funktionieren sie jedoch nicht und stürzen mit der folgenden Ausnahme ab:

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

Dies ist darauf zurückzuführen, dass ab Android 24) das Uri für die Adressierung der heruntergeladenen Datei geändert wurde. Beispielsweise wurde eine Installationsdatei mit dem Namen appName.apk Gespeichert auf dem primären externen Dateisystem der App mit dem Paketnamen com.example.test wäre wie

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

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

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

für API 24 und höher.

Weitere Details dazu finden Sie hier und ich werde es nicht durchgehen.

Um die Frage für targetSdkVersion von 24 Und höher zu beantworten, müssen Sie die folgenden Schritte ausführen: Fügen Sie dem AndroidManifest.xml Folgendes hinzu:

<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 zum Ordner xml in res in src, main hinzu:

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

Das pathName ist das im obigen Beispiel für den Inhalt gezeigte und pathValue ist der tatsächliche Pfad auf dem System. Es wäre eine gute Idee, ein "." (ohne Anführungszeichen) für pathValue, wenn Sie kein zusätzliches Unterverzeichnis hinzufügen möchten.

  1. Schreiben Sie den folgenden Code, um das 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();
    

Es ist auch keine Berechtigung erforderlich, wenn Sie in das private Verzeichnis Ihrer eigenen App auf dem externen Dateisystem schreiben.

Ich habe eine AutoUpdate-Bibliothek geschrieben hier , in der ich das oben Genannte verwendet habe.

35
Ali Nem

Nun, ich habe tiefer gegraben und habe Quellen der PackageInstaller-Anwendung von Android Source gefunden.

https://github.com/Android/platform_packages_apps_packageinstaller

Vom Manifest habe ich festgestellt, dass es eine Erlaubnis erfordert:

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

Der eigentliche Installationsvorgang 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);
26
Alkersan

Ich möchte nur die Tatsache mitteilen, dass meine APK-Datei in meinem App-Datenverzeichnis gespeichert wurde und dass ich die Berechtigungen für die APK-Datei ändern musste, damit sie weltweit lesbar ist, damit sie auf diese Weise installiert werden kann, andernfalls das System warf "Parse error: Es gibt ein Problem beim Parsen des Pakets"; So verwendet die Lösung von @Horaceman:

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

Folge diesen Schritten:

1 - Füge dem AndroidManifest.xml folgendes hinzu:

<provider
        Android:name="Android.support.v4.content.FileProvider"
        Android:authorities="${applicationId}.provider"
        Android:exported="false"
        Android:grantUriPermissions="true">
        <meta-data
            Android:name="Android.support.FILE_PROVIDER_PATHS"
            Android:resource="@xml/paths"/>
    </provider>

2 - Füge die folgende paths.xml-Datei zum xml-Ordner hinzu (falls nicht vorhanden, erstelle sie) auf res in src, main

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

Der Pfadname ist der im obigen Beispiel für den Inhalt uri gezeigte und der Pfadwert ist der tatsächliche Pfad im System. Es wäre eine gute Idee, ein "." für pathValue oben, wenn Sie kein zusätzliches Unterverzeichnis hinzufügen möchten. 

3 - Schreiben Sie den folgenden Code in Run Your Apk-Dateien:

File file = "path of yor apk file";
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
    Uri fileUri = FileProvider.getUriForFile(getBaseContext(), getApplicationContext().getPackageName() + ".provider", 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);
    startActivity(intent);

} else {
    Intent intent = new Intent(Intent.ACTION_VIEW);
    intent.setDataAndType(Uri.fromFile(file), "application/vnd.Android.package-archive");
    intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
    startActivity(intent);
}
13
Lila saad

Ja es ist möglich. Dafür benötigen Sie jedoch das Telefon, um ungeprüfte Quellen zu installieren. Zum Beispiel tut slideMe das. Ich denke, das Beste, was Sie tun können, ist zu prüfen, ob die Anwendung vorhanden ist, und eine Absicht für den Android Market zu senden. Sie sollten etwas das URL-Schema für Android Market verwenden.

market://details?id=package.name

Ich weiß nicht genau, wie ich mit der Aktivität beginnen soll, aber wenn Sie eine Aktivität mit dieser Art von URL beginnen. Es sollte den Android-Markt öffnen und Ihnen die Wahl geben, die Apps zu installieren.

4

Wenn Sie den Download mit DownloadManager starten, müssen Sie ihn an einem externen Speicherort speichern, z. setDestinationInExternalFilesDir(c, null, "<your name here>).apk";. Die Absicht mit einem Paketarchiv-Typ scheint das content: - Schema, das bei Downloads an einen internen Speicherort verwendet wird, nicht zu mögen, aber file:. (Der Versuch, den internen Pfad in ein File-Objekt zu packen und dann den Pfad abzurufen, funktioniert auch nicht, obwohl dies zu einer file: - URL führt, da die App die apk nicht analysiert. Sieht so aus, als müsste es sein extern sein.)

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

Eine weitere Lösung, bei der die empfangende App nicht fest codiert werden muss und daher sicherer ist:

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

Nur eine Erweiterung, wenn irgendjemand eine Bibliothek braucht, kann dies helfen. Dank an Raghav

2
IronBlossom

versuche dies

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

Fügen Sie zunächst die folgende Zeile zu AndroidManifest.xml hinzu:

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

Verwenden Sie dann den folgenden Code, um apk zu installieren:

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);
1
Abbas.moosavi

Vergessen Sie nicht, Berechtigungen anzufordern:

Android.Manifest.permission.WRITE_EXTERNAL_STORAGE 
Android.Manifest.permission.READ_EXTERNAL_STORAGE

Fügen Sie in AndroidManifest.xml den Anbieter und die Berechtigung hinzu:

<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 Sie die XML-Datei provider 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();
            }

        }

    }

    ...

}
1
amiron

UpdateNode bietet eine API für Android zur Installation von APK-Paketen aus einer anderen App .

Sie können Ihr Update einfach online definieren und die API in Ihre App integrieren - das ist es ...
Derzeit befindet sich die API im Beta-Status, Sie können jedoch bereits einige Tests selbst durchführen.

Abgesehen davon bietet UpdateNode auch die Anzeige von Nachrichten im gesamten System an.

Ich bin Teil des Client-Entwicklerteams und verwende zumindest die Nachrichtenfunktion für meine eigene Android-App.

Hier finden Sie eine Beschreibung zur Integration der API.

1
sarahara

Versuchen Sie folgendes - Schreiben Sie auf Manifest:

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

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

Dies kann anderen sehr helfen!

Zuerst:

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

Second: Für Android 7 und höher sollten Sie einen Anbieter wie nachfolgend beschrieben definieren!

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

Third: Definiere path.xml im res/xml-Ordner wie folgt! Ich benutze dieses path für internen Speicher, wenn Sie es in etwas anderes ändern wollen. Sie können zu diesem 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 Berechtigung im Manifest hinzufügen:

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

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


0
Hadi Note