Android 靜默方式實(shí)現(xiàn)批量安裝卸載應(yīng)用程序的深入分析
思路是這樣的,在XX/packages/apps目錄下有一個(gè)PackageInstaller的應(yīng)用程序,Android機(jī)器中安裝卸載都是由這個(gè)應(yīng)用程序完成的。但是它沒(méi)有批量安裝和卸載的功能,如果要在自己的應(yīng)用程序中添加批量安裝和卸載的功能,其實(shí)很簡(jiǎn)單,只需要參考PakcageInstaller里面的安裝卸載代碼加個(gè)循環(huán)就可以了。但值得注意的是在編譯的過(guò)程中必須復(fù)制PackageInstaller里面的Android.mk文件,修改文件為工程目錄名。
好了,廢話不再多說(shuō),下面是關(guān)鍵代碼
1、 Android.mk文件
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := PackageInstaller
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
LOCAL_PATH:= $(call my-dir)
include $(CLEAR_VARS)
LOCAL_MODULE_TAGS := optional
LOCAL_SRC_FILES := $(call all-subdir-java-files)
LOCAL_PACKAGE_NAME := PackageInstaller
LOCAL_CERTIFICATE := platform
include $(BUILD_PACKAGE)
2、PakcageInstaller.java文件(關(guān)鍵代碼)
package cn.ceadic.apkmgr;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.util.Log;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
import android.os.FileUtils;
public class PackageInstaller {
private File mTmpFile;
private final String TMP_FILE_NAME = "tmpCopy.apk";
private final static String TAG = "PackInstaller";
private Context mContext;
public PackageInstaller(Context context) {
mContext = context;
}
public void install(String path,String packageName){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)),
"application/vnd.android.package-archive");
mContext.startActivity(intent);
}
public void instatllBatch(String path, String packageName) {
Log.i(TAG, "path=" + path);
int installFlags = 0;
PackageManager pm = mContext.getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
Log.w(TAG, "Replacing package:" + packageName);
}
// Create temp file before invoking install api
mTmpFile = createTempPackageFile(path);
if (mTmpFile == null) {
// Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
// msg.arg1 = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
// mHandler.sendMessage(msg);
return;
}
Uri mPackageURI = Uri.parse("file://" + mTmpFile.getPath());
String installerPackageName = mContext.getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI, observer, installFlags,
installerPackageName);
}
private File createTempPackageFile(String filePath) {
File tmpPackageFile = mContext.getFileStreamPath(TMP_FILE_NAME);
if (tmpPackageFile == null) {
Log.w(TAG, "Failed to create temp file");
return null;
}
if (tmpPackageFile.exists()) {
tmpPackageFile.delete();
}
// Open file to make it world readable
FileOutputStream fos;
try {
fos = openFileOutput(TMP_FILE_NAME, MODE_WORLD_READABLE);
} catch (FileNotFoundException e1) {
Log.e(TAG, "Error opening file " + TMP_FILE_NAME);
return null;
}
try {
fos.close();
} catch (IOException e) {
Log.e(TAG, "Error opening file " + TMP_FILE_NAME);
return null;
}
File srcPackageFile = new File(filePath);
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
Log.w(TAG, "Failed to make copy of file: " + srcPackageFile);
return null;
}
return tmpPackageFile;
}
private class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
// Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
// msg.arg1 = returnCode;
// mHandler.sendMessage(msg);
Log.i(TAG, "====INSTALL_COMPLETE");
}
}
private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(boolean succeeded) {
// Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
// msg.arg1 = succeeded?SUCCEEDED:FAILED;
// mHandler.sendMessage(msg);
Log.i(TAG, "====UNINSTALL_COMPLETE");
}
}
public void uninstall(String packageName){
Uri packageURI = Uri.parse("package:" + packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE,
packageURI);
mContext.startActivity(uninstallIntent);
}
public void uninstallBatch(String packageName) {
PackageDeleteObserver observer = new PackageDeleteObserver();
mContext.getPackageManager().deletePackage(packageName, observer, 0);
}
}
package cn.ceadic.apkmgr;
import java.io.File;
import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import android.content.Context;
import android.content.Intent;
import android.content.pm.PackageInfo;
import android.content.pm.PackageManager;
import android.content.pm.PackageManager.NameNotFoundException;
import android.net.Uri;
import android.util.Log;
import android.content.pm.IPackageInstallObserver;
import android.content.pm.IPackageDeleteObserver;
import android.os.FileUtils;
public class PackageInstaller {
private File mTmpFile;
private final String TMP_FILE_NAME = "tmpCopy.apk";
private final static String TAG = "PackInstaller";
private Context mContext;
public PackageInstaller(Context context) {
mContext = context;
}
public void install(String path,String packageName){
Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.fromFile(new File(path)),
"application/vnd.android.package-archive");
mContext.startActivity(intent);
}
public void instatllBatch(String path, String packageName) {
Log.i(TAG, "path=" + path);
int installFlags = 0;
PackageManager pm = mContext.getPackageManager();
try {
PackageInfo pi = pm.getPackageInfo(packageName,
PackageManager.GET_UNINSTALLED_PACKAGES);
if (pi != null) {
installFlags |= PackageManager.INSTALL_REPLACE_EXISTING;
}
} catch (NameNotFoundException e) {
}
if ((installFlags & PackageManager.INSTALL_REPLACE_EXISTING) != 0) {
Log.w(TAG, "Replacing package:" + packageName);
}
// Create temp file before invoking install api
mTmpFile = createTempPackageFile(path);
if (mTmpFile == null) {
// Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
// msg.arg1 = PackageManager.INSTALL_FAILED_INSUFFICIENT_STORAGE;
// mHandler.sendMessage(msg);
return;
}
Uri mPackageURI = Uri.parse("file://" + mTmpFile.getPath());
String installerPackageName = mContext.getIntent().getStringExtra(
Intent.EXTRA_INSTALLER_PACKAGE_NAME);
PackageInstallObserver observer = new PackageInstallObserver();
pm.installPackage(mPackageURI, observer, installFlags,
installerPackageName);
}
private File createTempPackageFile(String filePath) {
File tmpPackageFile = mContext.getFileStreamPath(TMP_FILE_NAME);
if (tmpPackageFile == null) {
Log.w(TAG, "Failed to create temp file");
return null;
}
if (tmpPackageFile.exists()) {
tmpPackageFile.delete();
}
// Open file to make it world readable
FileOutputStream fos;
try {
fos = openFileOutput(TMP_FILE_NAME, MODE_WORLD_READABLE);
} catch (FileNotFoundException e1) {
Log.e(TAG, "Error opening file " + TMP_FILE_NAME);
return null;
}
try {
fos.close();
} catch (IOException e) {
Log.e(TAG, "Error opening file " + TMP_FILE_NAME);
return null;
}
File srcPackageFile = new File(filePath);
if (!FileUtils.copyFile(srcPackageFile, tmpPackageFile)) {
Log.w(TAG, "Failed to make copy of file: " + srcPackageFile);
return null;
}
return tmpPackageFile;
}
private class PackageInstallObserver extends IPackageInstallObserver.Stub {
public void packageInstalled(String packageName, int returnCode) {
// Message msg = mHandler.obtainMessage(INSTALL_COMPLETE);
// msg.arg1 = returnCode;
// mHandler.sendMessage(msg);
Log.i(TAG, "====INSTALL_COMPLETE");
}
}
private class PackageDeleteObserver extends IPackageDeleteObserver.Stub {
public void packageDeleted(boolean succeeded) {
// Message msg = mHandler.obtainMessage(UNINSTALL_COMPLETE);
// msg.arg1 = succeeded?SUCCEEDED:FAILED;
// mHandler.sendMessage(msg);
Log.i(TAG, "====UNINSTALL_COMPLETE");
}
}
public void uninstall(String packageName){
Uri packageURI = Uri.parse("package:" + packageName);
Intent uninstallIntent = new Intent(Intent.ACTION_DELETE,
packageURI);
mContext.startActivity(uninstallIntent);
}
public void uninstallBatch(String packageName) {
PackageDeleteObserver observer = new PackageDeleteObserver();
mContext.getPackageManager().deletePackage(packageName, observer, 0);
}
}
3、別忘記添加權(quán)限
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />
<uses-permission android:name="android.permission.DELETE_PACKAGES" />
<uses-permission android:name="android.permission.CLEAR_APP_CACHE" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.CLEAR_APP_USER_DATA" />
以上代碼在Android2.1的SDK中編譯通過(guò),并正確批量安裝卸載應(yīng)用程序
- Android apk安裝替換卸載廣播的實(shí)現(xiàn)代碼
- android監(jiān)聽(tīng)安裝和卸載示例
- android實(shí)現(xiàn)靜默安裝與卸載的方法
- 使用python編寫(xiě)批量卸載手機(jī)中安裝的android應(yīng)用腳本
- Android實(shí)現(xiàn)用代碼簡(jiǎn)單安裝和卸載APK的方法
- 在Android 模擬器上安裝和卸載APK包的方法
- Android編程實(shí)現(xiàn)監(jiān)控apk安裝,卸載,替換的方法
- Android編程之軟件的安裝和卸載方法
- Android 靜默安裝和卸載的方法
- Android編程監(jiān)聽(tīng)APK安裝與刪除等過(guò)程的方法
相關(guān)文章
解決Android WebView攔截url,視頻播放加載失敗的問(wèn)題
這篇文章主要介紹了解決Android WebView攔截url,視頻播放加載失敗的問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android中HttpURLConnection與HttpClient的使用與封裝
這篇文章主要介紹了Android中HttpURLConnection與HttpClient的使用以及封裝方法,感興趣的小伙伴們可以參考一下2016-03-03
Android 給RecyclerView添加分割線的具體步驟(分享)
下面小編就為大家?guī)?lái)一篇Android 給RecyclerView添加分割線的具體步驟(分享)。小編覺(jué)得挺不錯(cuò)的,現(xiàn)在就分享給大家,也給大家做個(gè)參考。一起跟隨小編過(guò)來(lái)看看吧2017-04-04
Android中Volley框架進(jìn)行請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的使用
這篇文章主要介紹了Android中Volley框架進(jìn)行請(qǐng)求網(wǎng)絡(luò)數(shù)據(jù)的使用,本文給大家介紹的非常詳細(xì)具有參考借鑒價(jià)值,需要的朋友可以參考下2016-10-10
利用 kotlin 的方式自定義回調(diào)事件(kotlin函數(shù)參數(shù))
這篇文章主要介紹了利用 kotlin 的方式自定義回調(diào)事件(kotlin函數(shù)參數(shù)),具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧2020-03-03
Android自定義雙向進(jìn)度條的實(shí)現(xiàn)代碼
本篇文章主要介紹了Android自定義雙向進(jìn)度條的實(shí)現(xiàn)代碼,非常具有實(shí)用的價(jià)值,有興趣的同學(xué)一起來(lái)了解一下2017-09-09
Android App中ViewPager所帶來(lái)的滑動(dòng)沖突問(wèn)題解決方法
Android中我們經(jīng)常使用ViewPager配合Fragment實(shí)現(xiàn)視圖滑動(dòng),但在實(shí)際操作中又會(huì)經(jīng)常發(fā)生方向上的沖突問(wèn)題,這里我們就來(lái)總結(jié)一下Android App中ViewPager所帶來(lái)的滑動(dòng)沖突問(wèn)題解決方法:2016-06-06
android開(kāi)發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解
在本篇文章里小編給大家整理的是關(guān)于android開(kāi)發(fā)環(huán)境中SDK文件夾下的所需內(nèi)容詳解,有興趣的朋友們參考學(xué)習(xí)下。2019-09-09

