安装模式及安装自启动
1:下载apk
InputStream in=null;
FileOutputStream out = null;
try {
URL url = new URL(urlStr);
HttpURLConnection urlConnection = (HttpURLConnection) url.openConnection();
urlConnection.setRequestMethod("GET");
urlConnection.setDoOutput(false);
urlConnection.setConnectTimeout(10 * 1000);
urlConnection.setReadTimeout(30 * 1000);
urlConnection.setRequestProperty("Connection", "Keep-Alive");
urlConnection.setRequestProperty("Charset", "UTF-8");
urlConnection.setRequestProperty("Accept-Encoding", "gzip, deflate");
urlConnection.connect();
long bytetotal = urlConnection.getContentLength();
long bytesum = 0;
int byteread = 0;
in = urlConnection.getInputStream();
//保存 apk
File apkFile = StorageUtils.getCacheFile(this,appName,apkVersion);
out = new FileOutputStream(apkFile);
byte[] buffer = new byte[BUFFER_SIZE];
int oldProgress = 0;
while ((byteread = in.read(buffer)) != -1) {
bytesum += byteread;
out.write(buffer, 0, byteread);
int progress = (int) (bytesum * 100L / bytetotal);
// 如果进度与之前进度相等,则不更新,如果更新太频繁,否则会造成界面卡顿
if (progress != oldProgress) {
updateProgress(progress);
}
oldProgress = progress;
}
2:一般user安装
/**
* 点击系统通知栏安装
* @param apkFile
* @throws IOException
*/
public static void installByNotification (Context context,File apkFile) throws IOException {
NotificationManager mNotifyManager = (NotificationManager)context.getSystemService(Context.NOTIFICATION_SERVICE);
NotificationCompat.Builder mBuilder = new NotificationCompat.Builder(context);
String appName=context.getString(context.getApplicationInfo().labelRes);
int icon=context.getApplicationInfo().icon;
mBuilder.setContentTitle(appName).setSmallIcon(icon);
mBuilder.setContentText("下载成功").setProgress(0, 0, false);
Intent installAPKIntent = new Intent(Intent.ACTION_VIEW);
//如果没有设置SDCard写权限,或者没有sdcard,apk文件保存在内存中,需要授予权限才能安装
String[] command = {"chmod","777",apkFile.toString()};
ProcessBuilder builder = new ProcessBuilder(command);
builder.start();
installAPKIntent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
//installAPKIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//installAPKIntent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//installAPKIntent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
PendingIntent pendingIntent = PendingIntent.getActivity(context, 0, installAPKIntent, PendingIntent.FLAG_UPDATE_CURRENT);
mBuilder.setContentIntent(pendingIntent);
Notification noti = mBuilder.build();
noti.flags = Notification.FLAG_AUTO_CANCEL;
mNotifyManager.notify(0, noti);
}
3:取得root权限静默安装
/**
* 取得root权限实现静默安装
* @param apkPath
* @return
*/
private static boolean rootClientInstall(String apkPath){
PrintWriter PrintWriter = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("su");
// Log.v("apkPath--",apkPath);
PrintWriter = new PrintWriter(process.getOutputStream());
PrintWriter.println("chmod 777 "+apkPath);
PrintWriter.println("export LD_LIBRARY_PATH=/vendor/lib:/system/lib");
PrintWriter.println("pm install -r " + apkPath);
// PrintWriter.println("exit");
PrintWriter.flush();
PrintWriter.close();
int value = process.waitFor();
return returnResult(value);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(process!=null){
process.destroy();
}
}
return false;
}
/**
* 判断手机是否有root权限
*/
private static boolean hasRootPermission(){
PrintWriter PrintWriter = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("su");//执行su是向系统请求root权限,赋给当前进程
PrintWriter = new PrintWriter(process.getOutputStream());
PrintWriter.flush();
PrintWriter.close();
int value = process.waitFor();
return returnResult(value);
} catch (Exception e) {
e.printStackTrace();
}finally{
if(process!=null){
process.destroy();
}
}
return false;
}
4:获取系统权限静默安装||root权限安装
/**
* 系统内置rom静默安装或root权限安装
* @param apkPath
* @return
*/
我用的是方法二,方法一没有用过。
注:两种方法都不一定适用于所有android系统。
方法一:需要在Android系统源码的环境下用make来编译:
在应用程序的 AndroidManifest.xml 中的 manifest 节点中加入 android:sharedUserId="android.uid.system" 这个属性
修改Android.mk文件,加入LOCAL_CERTIFICATE := platform这一行
使用mm命令来编译,生成的apk就有修改系统时间的权限了。
方法二:使用目标系统的platform密钥来重新给apk文件签名。这步比较麻烦,首先找到密钥文件,在Android源码目录中的位置 是"build\target\product\security",下面的platform.pk8和platform.x509.pem两个文件。然 后用And roid提供的Signapk工具来签名,signapk的源代码是在"build\tools\signapk"下,用法为"signapk platform.x509.pem platform.pk8 input.apk output.apk",文件名最好使用绝对路径防止找不到,也可以修改源代码直接使用。
public static String installSilent(Context context, String filePath,boolean isRoot) {
return installSilent(context, filePath, " -r " + "-f", isRoot);
}//isRoot = true (root权限) isRoot=false(系统权限)
public static String installSilent(Context context, String filePath, String pmParams,boolean isRoot){
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(), isRoot, true);
if (commandResult.successMsg != null
&& (commandResult.successMsg.contains("Success") || commandResult.successMsg.contains("success"))) {
Toast.makeText(context,"更新成功,正在重启!",Toast.LENGTH_SHORT).show();
return "INSTALL_SUCCEEDED";
}
return "INSTALL_FAILED_OTHER";
}
public static CommandResult execCommand(String command, boolean isRoot, boolean isNeedResultMsg) {
return execCommand(new String[] {command}, isRoot, isNeedResultMsg);
}
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 ? "su" : "sh");
os = new DataOutputStream(process.getOutputStream());
for (String command : commands) {
if (command == null) {
continue;
}
// donnot use os.writeBytes(commmand), avoid chinese charset error
os.write(command.getBytes());
os.writeBytes("\n");
os.flush();
}
os.writeBytes("exit\n");
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 {
/** result of command **/
public int result;
/** success message of command result **/
public String successMsg;
/** error message of command result **/
public String errorMsg;
public CommandResult(int result) {
this.result = result;
}
public CommandResult(int result, String successMsg, String errorMsg) {
this.result = result;
this.successMsg = successMsg;
this.errorMsg = errorMsg;
}
}
5:判断软件类型
/**
* 是否为系统软件
* @param pInfo
* @return
*/
private static boolean isSystemApp(PackageInfo pInfo) {
if(pInfo == null ) return false ;
return ((pInfo.applicationInfo.flags & ApplicationInfo.FLAG_SYSTEM) != 0);
}
/**
* 是否为系统更新软件
* @param pInfo
* @return
*/
private static boolean isSystemUpdateApp(PackageInfo pInfo) {
if(pInfo == null ) return false ;
return ((pInfo.applicationInfo.flags & ApplicationInfo.FLAG_UPDATED_SYSTEM_APP) != 0);
}
/**
* 是否为用户软件
* @param pInfo
* @return
*/
private static boolean isUserApp(PackageInfo pInfo) {
if(pInfo == null ) return false ;
return (!isSystemApp(pInfo) && !isSystemUpdateApp(pInfo));
}
6:安装完毕广播自启动
if(intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)){
String packageName = intent.getDataString().substring(8);
Log.v("install app----", packageName);
Intent newIntent = new Intent();
newIntent.setClassName("com.example.********","com.example.*******"+ ".ui.activity.SplashActivity");
newIntent.setAction("android.intent.action.MAIN");
newIntent.addCategory("android.intent.category.LAUNCHER");
newIntent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(newIntent);
checkDownloadApk(context);
}
广播注册
<receiver android:name=".ui.java.AppBroadcastServer">
<intent-filter>
<action android:name="android.intent.action.PACKAGE_REPLACED" />
<data android:scheme="package" />
<!-- 注意!! 这句必须要加,否则接收不到BroadCast -->
</intent-filter>
</receiver>
安装权限添加
<uses-permission android:name="android.permission.INSTALL_PACKAGES" />