市面上很多应用都实现了静默安装的功能,例如各种手机市场。但是很多应用
必须要有静默安装的功能(各种电梯或者地铁广告机),因为这些设备都不会
有人去操作。
本文介绍的静默安装的方式是通过命令行的方式,方法是通过在网上搜集自己
整理得来,只适用于已Root设备,只在4.2.2设备上测试可行,其他的设备没有
Root权限,因此还不知道可行不可行。
主题安装代码来自网络,本文将它整理在一个类中,去掉了不需要的部分。
整理代码来自:【根据他的提示整理,感谢 】【GitHub】
下面贴出完整代码:
public class InstallUtils {
// 请求权限
public static final String COMMAND_SU = "su";
public static final String COMMAND_SH = "sh";
public static final String COMMAND_EXIT = "exit\n";
public static final String COMMAND_LINE_END = "\n";
public static final int APP_INSTALL_AUTO = 0;
public static final int APP_INSTALL_INTERNAL = 1;
public static final int APP_INSTALL_EXTERNAL = 2;
public static final int INSTALL_SUCCEEDED = 1;
public static final int INSTALL_FAILED_ALREADY_EXISTS = -1;
public static final int INSTALL_FAILED_INVALID_APK = -2;
public static final int INSTALL_FAILED_INVALID_URI = -3;
public static final int INSTALL_FAILED_INSUFFICIENT_STORAGE = -4;
public static final int INSTALL_FAILED_DUPLICATE_PACKAGE = -5;
public static final int INSTALL_FAILED_NO_SHARED_USER = -6;
public static final int INSTALL_FAILED_UPDATE_INCOMPATIBLE = -7;
public static final int INSTALL_FAILED_SHARED_USER_INCOMPATIBLE = -8;
public static final int INSTALL_FAILED_MISSING_SHARED_LIBRARY = -9;
public static final int INSTALL_FAILED_REPLACE_COULDNT_DELETE = -10;
public static final int INSTALL_FAILED_DEXOPT = -11;
public static final int INSTALL_FAILED_OLDER_SDK = -12;
public static final int INSTALL_FAILED_CONFLICTING_PROVIDER = -13;
public static final int INSTALL_FAILED_NEWER_SDK = -14;
public static final int INSTALL_FAILED_TEST_ONLY = -15;
public static final int INSTALL_FAILED_CPU_ABI_INCOMPATIBLE = -16;
public static final int INSTALL_FAILED_MISSING_FEATURE = -17;
public static final int INSTALL_FAILED_CONTAINER_ERROR = -18;
public static final int INSTALL_FAILED_INVALID_INSTALL_LOCATION = -19;
public static final int INSTALL_FAILED_MEDIA_UNAVAILABLE = -20;
public static final int INSTALL_FAILED_VERIFICATION_TIMEOUT = -21;
public static final int INSTALL_FAILED_VERIFICATION_FAILURE = -22;
public static final int INSTALL_FAILED_PACKAGE_CHANGED = -23;
public static final int INSTALL_FAILED_UID_CHANGED = -24;
public static final int INSTALL_PARSE_FAILED_NOT_APK = -100;
public static final int INSTALL_PARSE_FAILED_BAD_MANIFEST = -101;
public static final int
INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION = -102;
public static final int
INSTALL_PARSE_FAILED_NO_CERTIFICATES = -103;
public static final int
INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES = -104;
public static final int
INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING = -105;
public static final int INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME = -106;
public static final int INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID = -107;
public static final int INSTALL_PARSE_FAILED_MANIFEST_MALFORMED = -108;
public static final int INSTALL_PARSE_FAILED_MANIFEST_EMPTY = -109;
public static final int INSTALL_FAILED_INTERNAL_ERROR = -110;
public static final int INSTALL_FAILED_OTHER = -1000000;
public static final int install(Context context, String filePath) {
// 判断设备是否Root,已Root则静默安装,否则跳转系统安装界面
if (isSystemApplication(context) || checkRootPermission()) {
return installSilent(context, filePath);
}
return installNormal(context, filePath) ? INSTALL_SUCCEEDED : INSTALL_FAILED_INVALID_URI;
}
public static boolean installNormal(Context context, String filePath) {
Intent i = new Intent(Intent.ACTION_VIEW);
File file = new File(filePath);
if (file == null || !file.exists() ||
!file.isFile() || file.length() <= 0) {
return false;
}
i.setDataAndType(Uri.parse("file://" + filePath), "application/vnd.android.package-archive");
i.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(i);
return true;
}
public static int installSilent(Context context, String filePath) {
return installSilent(context, filePath, " -r " + getInstallLocationParams());
}
private static String getInstallLocationParams() {
int location = getInstallLocation();
switch (location) {
case APP_INSTALL_INTERNAL:
return "-f";
case APP_INSTALL_EXTERNAL:
return "-s";
}
return "";
}
public static int getInstallLocation() {
CommandResult commandResult = execCommand("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm get-install-location", false, true);
if (commandResult.result == 0 && commandResult.successMsg != null && commandResult.successMsg.length() > 0) {
try {
int location = Integer.parseInt(commandResult.successMsg.substring(0, 1));
switch (location) {
case APP_INSTALL_INTERNAL:
return APP_INSTALL_INTERNAL;
case APP_INSTALL_EXTERNAL:
return APP_INSTALL_EXTERNAL;
}
} catch (NumberFormatException e) {
e.printStackTrace();
Log.e(TAG, "pm get-install-location error");
}
}
return APP_INSTALL_AUTO;
}
public static boolean isSystemApplication(Context context) {
if (context == null) {
return false;
}
return isSystemApplication(context, context.getPackageName());
}
public static boolean isSystemApplication(Context context, String packageName) {
if (context == null) {
return false;
}
return isSystemApplication(context.getPackageManager(), packageName);
}
public static boolean isSystemApplication(PackageManager packageManager, String packageName) {
if (packageManager == null || packageName == null || packageName.length() == 0) {
return false;
}
try {
ApplicationInfo app = packageManager.getApplicationInfo(packageName, 0);
return (app != null && (app.flags & ApplicationInfo.FLAG_SYSTEM) > 0);
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
}
return false;
}
public static boolean checkRootPermission() {
return execCommand("echo root", true, false).result == 0;
}
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(new String[]{command}, isRoot, isNeedResultMsg);
}
public static int installSilent(Context context, String filePath, String pmParams) {
if (filePath == null || filePath.length() == 0) {
return INSTALL_FAILED_INVALID_URI;
}
File file = new File(filePath);
if (file == null || file.length() <= 0 || !file.exists() || !file.isFile()) {
return INSTALL_FAILED_INVALID_URI;
}
StringBuilder command = new StringBuilder().append("LD_LIBRARY_PATH=/vendor/lib*:/system/lib* pm install ")
.append(pmParams == null ? "" : pmParams).append(" ").append(filePath.replace(" ", "\\ "));
CommandResult commandResult = execCommand(command.toString(), !isSystemApplication(context), true);
if (commandResult.successMsg != null
&& (commandResult.successMsg.contains("Success") || commandResult.successMsg.contains("success"))) {
return INSTALL_SUCCEEDED;
}
Log.e(TAG, new StringBuilder().append("installSilent successMsg:").append(commandResult.successMsg)
.append(", ErrorMsg:").append(commandResult.errorMsg).toString());
if (commandResult.errorMsg == null) {
return INSTALL_FAILED_OTHER;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_ALREADY_EXISTS")) {
return INSTALL_FAILED_ALREADY_EXISTS;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_APK")) {
return INSTALL_FAILED_INVALID_APK;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_URI")) {
return INSTALL_FAILED_INVALID_URI;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_INSUFFICIENT_STORAGE")) {
return INSTALL_FAILED_INSUFFICIENT_STORAGE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_DUPLICATE_PACKAGE")) {
return INSTALL_FAILED_DUPLICATE_PACKAGE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_NO_SHARED_USER")) {
return INSTALL_FAILED_NO_SHARED_USER;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_UPDATE_INCOMPATIBLE")) {
return INSTALL_FAILED_UPDATE_INCOMPATIBLE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_SHARED_USER_INCOMPATIBLE")) {
return INSTALL_FAILED_SHARED_USER_INCOMPATIBLE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_SHARED_LIBRARY")) {
return INSTALL_FAILED_MISSING_SHARED_LIBRARY;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_REPLACE_COULDNT_DELETE")) {
return INSTALL_FAILED_REPLACE_COULDNT_DELETE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_DEXOPT")) {
return INSTALL_FAILED_DEXOPT;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_OLDER_SDK")) {
return INSTALL_FAILED_OLDER_SDK;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_CONFLICTING_PROVIDER")) {
return INSTALL_FAILED_CONFLICTING_PROVIDER;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_NEWER_SDK")) {
return INSTALL_FAILED_NEWER_SDK;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_TEST_ONLY")) {
return INSTALL_FAILED_TEST_ONLY;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_CPU_ABI_INCOMPATIBLE")) {
return INSTALL_FAILED_CPU_ABI_INCOMPATIBLE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_MISSING_FEATURE")) {
return INSTALL_FAILED_MISSING_FEATURE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_CONTAINER_ERROR")) {
return INSTALL_FAILED_CONTAINER_ERROR;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_INVALID_INSTALL_LOCATION")) {
return INSTALL_FAILED_INVALID_INSTALL_LOCATION;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_MEDIA_UNAVAILABLE")) {
return INSTALL_FAILED_MEDIA_UNAVAILABLE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_TIMEOUT")) {
return INSTALL_FAILED_VERIFICATION_TIMEOUT;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_VERIFICATION_FAILURE")) {
return INSTALL_FAILED_VERIFICATION_FAILURE;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_PACKAGE_CHANGED")) {
return INSTALL_FAILED_PACKAGE_CHANGED;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_UID_CHANGED")) {
return INSTALL_FAILED_UID_CHANGED;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NOT_APK")) {
return INSTALL_PARSE_FAILED_NOT_APK;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_MANIFEST")) {
return INSTALL_PARSE_FAILED_BAD_MANIFEST;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION")) {
return INSTALL_PARSE_FAILED_UNEXPECTED_EXCEPTION;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_NO_CERTIFICATES")) {
return INSTALL_PARSE_FAILED_NO_CERTIFICATES;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES")) {
return INSTALL_PARSE_FAILED_INCONSISTENT_CERTIFICATES;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING")) {
return INSTALL_PARSE_FAILED_CERTIFICATE_ENCODING;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME")) {
return INSTALL_PARSE_FAILED_BAD_PACKAGE_NAME;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID")) {
return INSTALL_PARSE_FAILED_BAD_SHARED_USER_ID;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_MALFORMED")) {
return INSTALL_PARSE_FAILED_MANIFEST_MALFORMED;
}
if (commandResult.errorMsg.contains("INSTALL_PARSE_FAILED_MANIFEST_EMPTY")) {
return INSTALL_PARSE_FAILED_MANIFEST_EMPTY;
}
if (commandResult.errorMsg.contains("INSTALL_FAILED_INTERNAL_ERROR")) {
return INSTALL_FAILED_INTERNAL_ERROR;
}
return INSTALL_FAILED_OTHER;
}
public static CommandResult execCommand(String[] commands, boolean isRoot, boolean isNeedResultMsg) {
int result = -1;
if (commands == null || commands.length == 0) {
return new CommandResult(result, null, null);
}
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = null;
StringBuilder errorMsg = null;
DataOutputStream os = null;
try {
process = Runtime.getRuntime().exec(isRoot ? COMMAND_SU : COMMAND_SH);
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
os.write(command.getBytes());
os.writeBytes(COMMAND_LINE_END);
os.flush();
}
os.writeBytes(COMMAND_EXIT);
os.flush();
result = process.waitFor();
// get command result
if (isNeedResultMsg) {
successMsg = new StringBuilder();
errorMsg = new StringBuilder();
successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));
String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}
}
} catch (IOException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if (os != null) {
os.close();
}
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}
return new CommandResult(result, successMsg == null ? null : successMsg.toString(), errorMsg == null ? null
: errorMsg.toString());
}
public static class CommandResult {
public int result;
public String successMsg;
public String errorMsg;
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
//安装完成打开
public static void openApk(Context context, String packageName) {
Intent openIntent = context.getPackageManager().getLaunchIntentForPackage(packageName);
if (openIntent != null) {
openIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(openIntent);
}
}
}
代码的思路很清晰,不用过多讲解也能看懂。
写完代码运行之后发现还并不能静默安装,会提示[INSTALL_PARSE_FAILED_NO_CERTIFICATES]
错误,安装失败,就是说这个被安装的应用需要签名【注意:是被安装应用】。