Saya tertarik untuk mengetahui apakah mungkin untuk menginstal secara sistematis APK yang diunduh secara dinamis dari aplikasi Android khusus.
Saya tertarik untuk mengetahui apakah mungkin untuk menginstal secara sistematis APK yang diunduh secara dinamis dari aplikasi Android khusus.
Jawaban:
Anda dapat dengan mudah meluncurkan tautan play store atau prompt instal:
Intent promptInstall = new Intent(Intent.ACTION_VIEW)
.setDataAndType(Uri.parse("content:///path/to/your.apk"),
"application/vnd.android.package-archive");
startActivity(promptInstall);
atau
Intent goToMarket = new Intent(Intent.ACTION_VIEW)
.setData(Uri.parse("https://play.google.com/store/apps/details?id=com.package.name"));
startActivity(goToMarket);
Namun, Anda tidak dapat menginstal .apks tanpa izin eksplisit pengguna ; tidak kecuali perangkat dan program Anda di-root.
/sdcard, karena itu salah pada Android 2.2+ dan perangkat lain. Gunakan Environment.getExternalStorageDirectory()sebagai gantinya.
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);
Saya memiliki masalah yang sama dan setelah beberapa upaya, berhasil bagi saya dengan cara ini. Saya tidak tahu mengapa, tetapi mengatur data dan mengetik secara terpisah mengacaukan niat saya.
setData()akan menyebabkan parameter tipe dihapus. Anda HARUS menggunakan setDataAndType()jika Anda ingin memberikan nilai untuk keduanya. Di sini: developer.android.com/reference/android/content/…
Solusi yang diberikan untuk pertanyaan ini berlaku untuk targetSdkVersions 23 dan di bawah. Untuk Android N, yaitu API level 24, dan di atasnya, bagaimanapun, mereka tidak bekerja dan macet dengan Pengecualian berikut:
android.os.FileUriExposedException: file:///storage/emulated/0/... exposed beyond app through Intent.getData()
Ini disebabkan oleh fakta bahwa mulai dari Android 24, Uriuntuk menangani file yang diunduh telah berubah. Misalnya, file instalasi yang bernama appName.apkdisimpan pada sistem file eksternal utama dari aplikasi dengan nama paket com.example.testakan sama
file:///storage/emulated/0/Android/data/com.example.test/files/appName.apk
untuk API 23dan di bawah, sedangkan sesuatu seperti
content://com.example.test.authorityStr/pathName/Android/data/com.example.test/files/appName.apk
untuk API 24 dan di atas.
Rincian lebih lanjut tentang ini dapat ditemukan di sini dan saya tidak akan membahasnya.
Untuk menjawab pertanyaan untuk targetSdkVersiondari 24dan di atas, kita harus ikuti langkah berikut: Tambahkan berikut ke 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. Tambahkan paths.xmlfile berikut ke xmlfolder di resdalam 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>
The pathNameadalah bahwa ditunjukkan pada contoh uri konten teladan di atas dan pathValuemerupakan jalan yang sebenarnya pada sistem. Ini akan menjadi ide yang bagus untuk menempatkan "." (tanpa tanda kutip) untuk pathValue di atas jika Anda tidak ingin menambahkan subdirektori tambahan.
Tulis kode berikut untuk menginstal apk dengan nama appName.apkpada sistem file eksternal utama:
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();Tidak ada izin juga diperlukan saat menulis ke direktori pribadi aplikasi Anda pada sistem file eksternal.
Saya telah menulis perpustakaan AutoUpdate di sini di mana saya telah menggunakan di atas.
.authorityStrsetelah context.getPackageName()itu harus bekerja.
Baiklah, saya menggali lebih dalam, dan menemukan sumber aplikasi PackageInstaller dari Android Source.
https://github.com/android/platform_packages_apps_packageinstaller
Dari manifes saya menemukan bahwa itu memerlukan izin:
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
Dan proses instalasi yang sebenarnya terjadi setelah konfirmasi
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);
Saya hanya ingin berbagi fakta bahwa file apk saya disimpan ke direktori "Data" aplikasi saya dan bahwa saya perlu mengubah izin pada file apk agar dapat dibaca dunia agar dapat diinstal dengan cara itu, jika tidak, sistem melemparkan "Parse error: Ada Masalah Parsing Paket"; jadi gunakan solusi dari @Horaceman yang membuat:
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);
Ini bisa banyak membantu orang lain!
Pertama:
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();
}
}
Kedua: Untuk android 7 dan di atas Anda harus menentukan penyedia dalam manifes seperti di bawah ini!
<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>
Ketiga: Tentukan path.xml di folder res / xml seperti di bawah ini! Saya menggunakan jalur ini untuk penyimpanan internal jika Anda ingin mengubahnya ke sesuatu yang lain ada beberapa cara! Anda dapat membuka tautan ini: 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>
Keempat: Anda harus menambahkan izin ini dalam manifes:
<uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES"/>
Mengizinkan aplikasi meminta paket pemasangan. API penargetan aplikasi yang lebih dari 25 harus memiliki izin ini untuk menggunakan Intent.ACTION_INSTALL_PACKAGE.
Pastikan otoritas penyedia sama!
Iya itu mungkin. Tetapi untuk itu Anda memerlukan ponsel untuk menginstal sumber yang tidak diverifikasi. Sebagai contoh, slideMe melakukan itu. Saya pikir hal terbaik yang dapat Anda lakukan adalah memeriksa apakah aplikasi tersebut ada dan mengirim maksud untuk Android Market. Anda harus menggunakan sesuatu skema url untuk Android Market.
market://details?id=package.name
Saya tidak tahu persis bagaimana memulai aktivitas tetapi jika Anda memulai aktivitas dengan url semacam itu. Itu harus membuka pasar android dan memberi Anda pilihan untuk menginstal aplikasi.
Perlu dicatat bahwa jika Anda menggunakan DownloadManageruntuk memulai unduhan Anda, pastikan untuk menyimpannya ke lokasi eksternal misalnya setDestinationInExternalFilesDir(c, null, "<your name here>).apk";. Maksud dengan tipe paket-arsip tampaknya tidak seperti content:skema yang digunakan dengan unduhan ke lokasi internal, tetapi memang suka file:. (Mencoba untuk membungkus jalur internal menjadi objek File dan kemudian mendapatkan jalur tidak berfungsi baik, meskipun itu menghasilkan afile: url, karena aplikasi tidak akan menguraikan apk; sepertinya itu harus eksternal.)
Contoh:
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);
Jangan lupa untuk meminta izin:
android.Manifest.permission.WRITE_EXTERNAL_STORAGE
android.Manifest.permission.READ_EXTERNAL_STORAGE
Tambahkan AndroidManifest.xml penyedia dan izin:
<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>
Buat penyedia file 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>
Gunakan kode contoh di bawah ini:
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();
}
}
}
...
}
coba ini
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);
Pertama tambahkan baris berikut ke AndroidManifest.xml:
<uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions" />
Kemudian gunakan kode berikut untuk menginstal 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 menyediakan API untuk Android untuk menginstal paket APK dari dalam Aplikasi lain.
Anda bisa mendefinisikan Pembaruan Anda secara online dan mengintegrasikan API ke dalam Aplikasi Anda - hanya itu.
Saat ini API dalam keadaan Beta, tetapi Anda sudah dapat melakukan beberapa tes sendiri.
Selain itu, UpdateNode menawarkan juga menampilkan pesan melalui sistem - cukup berguna jika Anda ingin memberi tahu sesuatu yang penting bagi pengguna Anda.
Saya adalah bagian dari tim dev klien dan saya menggunakan setidaknya fungsi pesan untuk Aplikasi Android saya sendiri.
Coba ini - Tulis di Manifest:
uses-permission android:name="android.permission.INSTALL_PACKAGES"
tools:ignore="ProtectedPermissions"
Tulis Kode:
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);