您的位置:首页 > 移动开发

Android 如何静默安装app

2017-09-18 15:42 393 查看
Android 要想静默安装app,必须是系统应用或者具有Root权限,否则根本不可能实现静默安装。

本文假设你的app是系统应用(有系统签名,或者放在系统/system/app 或 /system/priv-app分区),则可以进行以下安装:

注意:静默安装还需要在你的AndroidManifest.xml中添加权限声明。该权限默认赋予系统应用,第三方应用即使声明了,也拿不到该权限!

[html]
view plain
copy

<!-- 静默安装 -->
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />

1. 有提示的安装(所有第三方应用都可以)

[java]
view plain
copy

Intent intent = new Intent(Intent.ACTION_VIEW);
intent.setDataAndType(Uri.parse("file://" + apkFilePath), "application/vnd.android.package-archive");
intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
mContext.startActivity(intent);

这是调用系统的AppInstaller,提示用户安装升级。
2. 静默安装:利用ProcessBuilder

[java]
view plain
copy

/**
* install slient
*
* @param filePath
* @return 0 means normal, 1 means file not exist, 2 means other exception error
*/
public static int installSilent(String filePath) {
File file = new File(filePath);
if (filePath == null || filePath.length() == 0 || file == null || file.length() <= 0 || !file.exists() || !file.isFile()) {
return 1;
}

String[] args = { "pm", "install", "-r", filePath };
ProcessBuilder processBuilder = new ProcessBuilder(args);
Process process = null;
BufferedReader successResult = null;
BufferedReader errorResult = null;
StringBuilder successMsg = new StringBuilder();
StringBuilder errorMsg = new StringBuilder();
int result;
try {
process = processBuilder.start();
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 (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}
if (process != null) {
process.destroy();
}
}

// TODO should add memory is not enough here
if (successMsg.toString().contains("Success") || successMsg.toString().contains("success")) {
result = 0;
} else {
result = 2;
}
Log.d("test-test", "successMsg:" + successMsg + ", ErrorMsg:" + errorMsg);
return result;
}

3. 静默安装:利用Runtime.getRuntime().exec()

[java]
view plain
copy

private static final String TAG = "test-test";

private static final int TIME_OUT = 60 * 1000;

private static String[] SH_PATH = {
"/system/bin/sh",
"/system/xbin/sh",
"/system/sbin/sh"
};

public static boolean executeInstallCommand(String filePath) {
String command = “pm install -r ” + filePath;
Process process = null;
DataOutputStream os = null;
StringBuilder successMsg = new StringBuilder();
StringBuilder errorMsg = new StringBuilder();
BufferedReader successResult = null;
BufferedReader errorResult = null;
try {
process = runWithEnv(getSuPath(), null);
if (process == null) {
return false;
}

successResult = new BufferedReader(new InputStreamReader(process.getInputStream()));
errorResult = new BufferedReader(new InputStreamReader(process.getErrorStream()));

os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("echo \"rc:\" $?\n");
os.writeBytes("exit\n");
os.flush();

String s;
while ((s = successResult.readLine()) != null) {
successMsg.append(s);
}
while ((s = errorResult.readLine()) != null) {
errorMsg.append(s);
}

// Handle a requested timeout, or just use waitFor() otherwise.
if (TIME_OUT > 0) {
long finish = System.currentTimeMillis() + TIME_OUT;
while (true) {
Thread.sleep(300);
if (!isProcessAlive(process)) {
break;
}

if (System.currentTimeMillis() > finish) {
Log.w(TAG, "Process doesn't seem to stop on it's own, assuming it's hanging");
// Note: 'finally' will call destroy(), but you might still see zombies.
return true;
}
}
} else {
process.waitFor();
}

// In order to consider this a success, we require to things: a) a proper exit value, and ...
if (process.exitValue() != 0) {
return false;
}

return true;

} catch (FileNotFoundException e) {
Log.w(TAG, "Failed to run command, " + e.getMessage());
return false;
} catch (IOException e) {
Log.w(TAG, "Failed to run command, " + e.getMessage());
return false;
} catch (InterruptedException e) {
Log.w(TAG, "Failed to run command, " + e.getMessage());
return false;
} finally {
if (os != null) {
try {
os.close();
} catch (IOException e) {
throw new RuntimeException(e);
}
}

try {
if (successResult != null) {
successResult.close();
}
if (errorResult != null) {
errorResult.close();
}
} catch (IOException e) {
e.printStackTrace();
}

if (process != null) {
try {
// Yes, this really is the way to check if the process is still running.
process.exitValue();
} catch (IllegalThreadStateException e) {
process.destroy();
}
}
}
}

private static Process runWithEnv(String command, String[] customEnv) throws IOException {
List<String> envList = new ArrayList<String>();
Map<String, String> environment = System.getenv();
if (environment != null) {
for (Map.Entry<String, String> entry : environment.entrySet()) {
envList.add(entry.getKey() + "=" + entry.getValue());
}
}

if (customEnv != null) {
for (String value : customEnv) {
envList.add(value);
}
}

String[] arrayEnv = null;
if (envList.size() > 0) {
arrayEnv = new String[envList.size()];
for (int i = 0; i < envList.size(); i++) {
arrayEnv[i] = envList.get(i);
}
}

Process process = Runtime.getRuntime().exec(command, arrayEnv);
return process;
}

/**
* Check whether a process is still alive. We use this as a naive way to implement timeouts.
*/
private static boolean isProcessAlive(Process p) {
try {
p.exitValue();
return false;
} catch (IllegalThreadStateException e) {
return true;
}
}

/** Get the SU file path if it exist */
private static String getSuPath() {
for (String p : SH_PATH) {
File sh = new File(p);
if (sh.exists()) {
return p;
}
}
return "su";
}

4. 静默安装:利用反射调用API-PackageManager.installPackage()

[java]
view plain
copy

public static void installSilentWithReflection(Context context, String filePath) {
try {
PackageManager packageManager = context.getPackageManager();
Method method = packageManager.getClass().getDeclaredMethod("installPackage",
new Class[] {Uri.class, IPackageInstallObserver.class, int.class, String.class} );
method.setAccessible(true);
File apkFile = new File(filePath);
Uri apkUri = Uri.fromFile(apkFile);

method.invoke(packageManager, new Object[] {apkUri, new IPackageInstallObserver.Stub() {
@Override
public void packageInstalled(String pkgName, int resultCode) throws RemoteException {
Log.d(TAG, "packageInstalled = " + pkgName + "; resultCode = " + resultCode) ;
}
}, Integer.valueOf(2), "com.ali.babasecurity.yunos"});
//PackageManager.INSTALL_REPLACE_EXISTING = 2;
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (Exception e) {
e.printStackTrace();
}
}

上面用到了反射调用,IPackageInstallObserver.class这个类在android sdk里面是没有的,您需要下载android_dependency.jar放到你工程的libs目录,这个jar提供了与PackageManager反射调用相关的类的定义。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: