Question

I`m intéressé à savoir s'il est possible d'installer un programme apk dynamiquement téléchargé à partir d'une application personnalisée Android.

Était-ce utile?

La solution

Vous pouvez facilement lancer un lien de magasin de jeu ou une installation rapide:

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

ou

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

Cependant, vous ne pouvez pas installer .apks sans l'utilisateur permission explicite ; pas à moins que l'appareil et votre programme prend ses racines.

Autres conseils

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

J'ai eu le même problème et après plusieurs tentatives, cela a fonctionné pour moi de cette façon. Je ne sais pas pourquoi, mais les données de réglage et le type séparément foiré mon intention.

Les solutions apportées à cette question sont applicables à targetSdkVersion s de 23 et ci-dessous. Pour Android N, à savoir le niveau de l'API 24, et au-dessus, cependant, ils ne fonctionnent pas et accident avec l'exception suivante:

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

Ceci est dû au fait que, à partir d'Android 24, le Uri pour traiter le fichier téléchargé a changé. Par exemple, un fichier d'installation nommé appName.apk stocké sur le système de fichiers externe principal de l'application avec le nom du package com.example.test serait comme

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

pour API 23 et ci-dessous, alors que quelque chose comme

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

pour API 24 et au-dessus.

Plus de détails sur ce qui peut être trouvé et je ne vais pas passer par là.

Pour répondre à la question targetSdkVersion de 24 et au-dessus, on doit suivre les étapes suivantes: Ajouter ce qui suit à l'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. Ajoutez le fichier paths.xml suivant dans le dossier xml sur res dans src, principale:

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

Le pathName est que le montre l'exemple de contenu à titre d'exemple ci-dessus et uri pathValue est la trajectoire réelle sur le système. Ce serait une bonne idée de mettre un « » (Sans les guillemets) pour pathValue dans ce qui précède, si vous ne voulez pas ajouter sous-répertoire supplémentaire.

  1. Ecrire le code suivant pour installer le apk avec le nom appName.apk sur le système de fichiers externe principal:

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

Aucune autorisation est également nécessaire lors de l'écriture dans le répertoire privé de votre propre application sur le système de fichiers externe.

J'ai écrit une bibliothèque AutoUpdate dans lequel je l'ai utilisé ci-dessus.

Eh bien, je fouillai plus profond, et a trouvé des sources d'application PackageInstaller d'Android Source.

https://github.com/android/platform_packages_apps_packageinstaller

De manifeste, je trouve que ce besoin d'une permission:

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

Et le véritable processus d'installation se produit après la confirmation

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

Je veux juste partager le fait que mon fichier apk a été enregistré dans mon application répertoire « données » et que je devais changer les autorisations sur le fichier apk pour être accessible en lecture afin de lui permettre d'être installé de cette façon, sinon le système a été lancer « erreur d'analyse: Il y a un problème Parsing le package »; donc en utilisant la solution de @Horaceman qui fait:

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

Une autre solution qui ne nécessite pas coder en dur l'application de réception et qui est donc plus sûr:

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

Oui, il est possible. Mais pour cela vous avez besoin du téléphone pour installer des sources non vérifiées. Par exemple, SlideMe fait cela. Je pense que la meilleure chose que vous pouvez faire est de vérifier si l'application est présente et envoyer une intention pour l'Android Market. vous devez utiliser quelque chose le schéma d'URL pour Android Market.

market://details?id=package.name

Je ne sais pas exactement comment démarrer l'activité, mais si vous commencez une activité avec ce genre d'URL. Il devrait ouvrir le marché Android et vous donner le choix d'installer les applications.

Il convient de noter que si vous utilisez le DownloadManager pour lancer le téléchargement, assurez-vous de l'enregistrer dans un emplacement externe par exemple setDestinationInExternalFilesDir(c, null, "<your name here>).apk";. L'intention avec un type package archive ne semble pas que le système de content: utilisé avec des téléchargements à un emplacement interne, mais fait comme file:. (Essayer d'envelopper le chemin interne dans un objet fichier, puis obtenir le chemin d'accès ne fonctionne pas non plus, même si elle se traduit par une url file:, comme l'application ne sera pas analyser l'APK, semble que cela doit être externe.)

Exemple:

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

Cela peut aider beaucoup d'autres!

Première:

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

Deuxième: pour Android 7 ci-dessus et vous devez définir un fournisseur dans le manifeste comme ci-dessous

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

Troisième: Définir path.xml dans res / dossier xml comme ci-dessous! J'utilise ce chemin pour le stockage interne si vous voulez changer quelque chose d'autre il y a quelques chemin! Vous pouvez aller à ce lien: 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: Vous devez ajouter cette autorisation dans le manifeste:

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

S'il vous plaît assurez-vous que les autorités des fournisseurs sont les mêmes!


Juste une extension, si quelqu'un a besoin d'une bibliothèque, puis cette pourrait aider. Merci à Raghav

essayer

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 fournit une API pour Android pour installer des paquets APK à l'intérieur une autre application.
Vous pouvez simplement définir votre mise à jour en ligne et d'intégrer l'API dans votre application - c'est tout.
Actuellement, l'API est en état bêta, mais vous pouvez déjà faire quelques tests vous-même.
A côté de cela, UpdateNode offre l'affichage des messages aussi bien que le système - très utile si vous voulez dire quelque chose d'important à vos utilisateurs.
Je fais partie de l'équipe de développement client et je utilise au moins la fonctionnalité de message pour mon propre App Android.

Voir ici une description comment intégrer l'API

D'abord ajoutez la ligne suivante à AndroidManifest.xml:

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

Ensuite, utilisez le code suivant pour installer 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);

Ne pas oublier de demander des autorisations:

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

Ajoutez à AndroidManifest.xml le fournisseur et l'autorisation:

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

Créer XML fournisseur de fichier 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>

Utilisez ci-dessous un exemple de code:

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

        }

    }

    ...

}

Essayer cette - Ecrire sur Manifest:

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

Recopiez le 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);
Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top