Anwendung installieren programmatisch auf Android
Frage
Ich habe Interesse zu wissen, ob es möglich ist, programmatisch eine dynamisch heruntergeladen apk aus einer benutzerdefinierten Android-Anwendung installiert werden.
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.
-
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!
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.
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);