Chcę wiedzieć, czy można programowo zainstalować dynamicznie pobieraną aplikację z niestandardowej aplikacji na Androida.
Chcę wiedzieć, czy można programowo zainstalować dynamicznie pobieraną aplikację z niestandardowej aplikacji na Androida.
Odpowiedzi:
Możesz łatwo uruchomić link do sklepu Play lub monit instalacyjny:
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setDataAndType(Uri.parse("content:///path/to/your.apk"),
"application/vnd.android.package-archive");
startActivity(promptInstall);
lub
Intent goToMarket = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("https://play.google.com/store/apps/details?id=com.package.name"));
startActivity(goToMarket);
Nie można jednak instalować plików .apks bez wyraźnej zgody użytkownika ; chyba że urządzenie i twój program są zrootowane.
/sdcard
, ponieważ jest to złe na Androidzie 2.2+ i innych urządzeniach. Użyj Environment.getExternalStorageDirectory()
zamiast tego.
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);
Miałem ten sam problem i po kilku próbach mi się to udało. Nie wiem dlaczego, ale osobne ustawianie danych i typów spieszyło moje zamiary.
setData()
spowoduje usunięcie parametru type. MUSISZ użyć, setDataAndType()
jeśli chcesz podać wartości dla obu. Tutaj: developer.android.com/reference/android/content/…
Rozwiązania dostarczone dla tego pytania mają zastosowanie do targetSdkVersion
s z 23 i poniżej. W przypadku systemu Android N, tj. Interfejsu API poziomu 24 i nowszego, nie działają one jednak i występują awarie z następującym wyjątkiem:
android.os.FileUriExposedException: file:///storage/emulated/0/... exposed beyond app through Intent.getData()
Wynika to z faktu, że począwszy od Androida 24 Uri
zmieniło się adresowanie pobranego pliku. Na przykład plik instalacyjny o nazwie appName.apk
przechowywany w głównym zewnętrznym systemie plików aplikacji z nazwą pakietu com.example.test
byłby taki jak
file:///storage/emulated/0/Android/data/com.example.test/files/appName.apk
dla API 23
i poniżej, podczas gdy coś podobnego
content://com.example.test.authorityStr/pathName/Android/data/com.example.test/files/appName.apk
za API 24
i powyżej.
Więcej informacji na ten temat można znaleźć tutaj i nie zamierzam przez to przechodzić.
Aby odpowiedzieć na pytanie o targetSdkVersion
z 24
i powyżej, trzeba wykonać następujące czynności: Dodaj następujące do 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. Dodaj następujący paths.xml
plik do xml
folderu res
w src, main:
<?xml version="1.0" encoding="utf-8"?>
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="pathName"
path="pathValue"/>
</paths>
To, pathName
co pokazano w przykładowym przykładzie treści powyżej i pathValue
jest rzeczywistą ścieżką w systemie. Dobrym pomysłem byłoby umieszczenie „”. (bez cudzysłowów) dla pathValue powyżej, jeśli nie chcesz dodawać żadnego dodatkowego podkatalogu.
Napisz następujący kod, aby zainstalować apk o nazwie appName.apk
w podstawowym zewnętrznym systemie plików:
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();
Żadne pozwolenie nie jest również konieczne przy zapisywaniu do prywatnego katalogu własnej aplikacji w zewnętrznym systemie plików.
Napisałem tutaj bibliotekę AutoUpdate , w której użyłem powyższego.
.authorityStr
po context.getPackageName()
tym, to powinno działać.
Cóż, kopałem głębiej i znalazłem źródła aplikacji PackageInstaller ze źródła Android.
https://github.com/android/platform_packages_apps_packageinstaller
Z manifestu stwierdziłem, że wymaga pozwolenia:
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
Rzeczywisty proces instalacji następuje po potwierdzeniu
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);
Chcę tylko podzielić się faktem, że mój plik apk został zapisany w katalogu „Data” w mojej aplikacji i że muszę zmienić uprawnienia do pliku apk, aby był czytelny na całym świecie, aby umożliwić jego instalację w ten sposób, w przeciwnym razie system rzucał „Błąd analizy: Wystąpił problem podczas analizowania pakietu”; więc używając rozwiązania @Horaceman, które sprawia:
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);
To może bardzo pomóc innym!
Pierwszy:
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();
}
}
Po drugie: w przypadku systemu Android 7 i nowszych należy zdefiniować dostawcę w manifeście, jak poniżej!
<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>
Po trzecie: Zdefiniuj path.xml w folderze res / xml jak poniżej! Używam tej ścieżki do pamięci wewnętrznej, jeśli chcesz zmienić ją na coś innego, istnieje kilka sposobów! Możesz przejść do tego linku: 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>
Po czwarte: Powinieneś dodać to zezwolenie w manifeście:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Zezwala aplikacji na żądanie instalacji pakietów. Aplikacje kierowane na interfejsy API większe niż 25 muszą posiadać to uprawnienie, aby móc korzystać z Intent.ACTION_INSTALL_PACKAGE.
Upewnij się, że władze dostawcy są takie same!
Tak, to możliwe. Ale do tego potrzebujesz telefonu, aby zainstalować niezweryfikowane źródła. Na przykład SlideMe to robi. Myślę, że najlepszą rzeczą, jaką możesz zrobić, to sprawdzić, czy aplikacja jest obecna i wysłać zamiar dla Android Market. powinieneś użyć czegoś w schemacie URL dla Android Market.
market://details?id=package.name
Nie wiem dokładnie, jak rozpocząć działanie, ale jeśli rozpoczniesz działanie z tego rodzaju adresem URL. Powinien otworzyć rynek Android Market i dać ci możliwość zainstalowania aplikacji.
Warto zauważyć, że jeśli używasz DownloadManager
do rozpoczęcia pobierania, pamiętaj, aby zapisać go w zewnętrznej lokalizacji, np setDestinationInExternalFilesDir(c, null, "<your name here>).apk";
. Intencja z typem pakietu archiwum nie wydaje się podobać do content:
schematu używanego do pobierania do wewnętrznej lokalizacji, ale się podoba file:
. (Próba zawinięcia wewnętrznej ścieżki w obiekt File, a następnie uzyskanie ścieżki również nie działa, nawet jeśli powoduje powstanie file:
adresu URL, ponieważ aplikacja nie analizuje pliku APK; wygląda na to, że musi być zewnętrzna.)
Przykład:
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);
Nie zapomnij poprosić o uprawnienia:
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
android.Manifest.permission.READ_EXTERNAL_STORAGE
Dodaj w AndroidManifest.xml dostawcę i pozwolenie:
<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>
Utwórz dostawcę plików XML 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>
Użyj poniższego przykładowego kodu:
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();
}
}
}
...
}
Spróbuj tego
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);
Najpierw dodaj następujący wiersz do pliku AndroidManifest.xml:
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
Następnie użyj następującego kodu, aby zainstalować 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);
UpdateNode zapewnia interfejs API dla Androida do instalowania pakietów APK z innej aplikacji.
Możesz po prostu zdefiniować swoją aktualizację online i zintegrować interfejs API z aplikacją - to wszystko.
Obecnie interfejs API jest w wersji Beta, ale możesz już samodzielnie wykonać kilka testów.
Poza tym UpdateNode oferuje również wyświetlanie komunikatów przez system - całkiem przydatne, jeśli chcesz powiedzieć coś ważnego dla swoich użytkowników.
Należę do zespołu programistów klienta i używam przynajmniej funkcji wiadomości w mojej własnej aplikacji na Androida.
Spróbuj tego - napisz na Manifeście:
uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions"
Napisz kod:
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);