Ich bin daran interessiert zu wissen, ob es möglich ist, dynamisch heruntergeladene apk-Programme von einer benutzerdefinierten Android-Anwendung programmgesteuert zu installieren.
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);
Intent goToMarket = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("market://details?id=com.package.name"));
startActivity(goToMarket);
Sie können jedoch keine .apks ohne explizite Berechtigung des Benutzers installieren. nicht, wenn das Gerät und Ihr Programm verwurzelt sind.
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.
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.
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.
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);
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);
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);
}
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.
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);
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);
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);
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);
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();
}
}
}
...
}
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.
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);
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!