我看网上很多同仁说,用这套代码可以完成静默安装,但不能重启,我也尝试过貌似确实不行。既然设备都ROOT了, 也静默安装了, 写个自启哪有这么难吗? ? ?
我分析是,原作者发的广播非延时的, 或者静默安装还没完成,应用就崩了,广播压根就没有发出去。所以我的思路是,直接抓应用异常,换一种自启思路,多加一个机制。
虽然设备可以获得root权限,理论上能获取所有权限,但如果不加下面权限,运行时会报错,另外 一定要注意 第一个权限 的等级 protectionLevel 也要加一下
<uses-permission
android:name="android.permission.INSTALL_PACKAGES"
android:protectionLevel="signature|privileged" />
<uses-permission android:name="android.permission.INTERACT_ACROSS_USERS" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
AndroidManifest.xml 根节点下添加
android:sharedUserId="android.uid.packageinstaller"
该代码来自网上一个大神撰写,测试可用
public class SystemCtrlUtil {
/**
* root下静默安装
* */
public static boolean rootSlienceInstallApk(String apkPath){
PrintWriter PrintWriter = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("su");
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下启动apk
* */
public static boolean rootStartApk(String packageName,String activityName){
boolean isSuccess = false;
String cmd = "am start -n " + packageName + "/" + activityName + " \n";
Process process = null;
try {
process = Runtime.getRuntime().exec(cmd);
int value = process.waitFor();
return returnResult(value);
} catch (Exception e) {
e.printStackTrace();
} finally{
if(process!=null){
process.destroy();
}
}
return isSuccess;
}
/**
* root下静默删除
* */
public static boolean rootSlienceUninstallApk(String packageName){
PrintWriter PrintWriter = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("su");
PrintWriter = new PrintWriter(process.getOutputStream());
PrintWriter.println("LD_LIBRARY_PATH=/vendor/lib:/system/lib ");
PrintWriter.println("pm uninstall "+packageName);
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权限
*/
public static boolean sysHasRootPerssion(){
PrintWriter PrintWriter = null;
Process process = null;
try {
process = Runtime.getRuntime().exec("su");
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;
}
/**
* root下执行cmd的返回值
* */
private static boolean returnResult(int value){
// 代表成功
if (value == 0) {
return true;
} else if (value == 1) { // 失败
return false;
} else { // 未知情况
return false;
}
}
/**
* 判断app是否有root权限
*/
public static boolean appHasRootPerssion(Context context){
return RootCommand("chmod 777 "+context.getPackageCodePath());
}
/**
* 应用程序运行命令获取 Root权限,设备必须已破解(获得ROOT权限)
* @param command 命令:String apkRoot="chmod 777 "+getPackageCodePath(); RootCommand(apkRoot);
* @return 应用程序是/否获取Root权限
*/
public static boolean RootCommand(String command)
{
Process process = null;
DataOutputStream os = null;
try
{
process = Runtime.getRuntime().exec("su");
os = new DataOutputStream(process.getOutputStream());
os.writeBytes(command + "\n");
os.writeBytes("exit\n");
os.flush();
return returnResult(process.waitFor());
} catch (Exception e)
{
Log.d("*** DEBUG ***", "ROOT REE" + e.getMessage());
return false;
} finally
{
try
{
if (os != null)
{
os.close();
}
process.destroy();
} catch (Exception e)
{
}
}
}
}
工具类使用
public static void sinlenceInstallApk(String apkPath, String apkName) {
Log.i(TAG, "sinlenceInstallApk():-----------------");
if (!SystemCtrlUtil.sysHasRootPerssion()) {
Log.e(TAG, "系统尚无Root权限");
return;
}
Log.i(TAG, "系统有Root权限");
File apkfile = new File(apkPath, apkName);
if (!apkfile.exists()) {
Log.e(TAG, "尚无APK文件");
return;
}
//4、静默安装
if (SystemCtrlUtil.rootSlienceInstallApk(apkPath + "/" + apkName)) {
Log.i(TAG, "静默安装成功");
//5、执行此命令后:BootReceiver 监听到Intent.ACTION_PACKAGE_REPLACED,然后自启动
if (SystemCtrlUtil.rootStartApk("com.winspread.adscreenplayer", "SplashActivity")) {
Log.i(TAG, "静默安装后启动APP成功");
} else {
Log.e(TAG, "静默安装后启动APP失败!!!");
}
} else {
Log.e(TAG, "静默安装失败!!!");
}
}
public class SystemEventReceiver extends BroadcastReceiver {
private static final String TAG = ">>>>>>SystemReceiver";
@Override
public void onReceive(Context context, Intent intent) {
String action = intent.getAction().toString();
switch (action) {
case "wits.action.reboot":
Log.i(TAG, "wits.action.reboot");
break;
case "wits.action.shutdown":
Log.i(TAG, "wits.action.shutdown");
break;
case "android.intent.action.BOOT_COMPLETED":
Log.i(TAG, "android.intent.action.BOOT_COMPLETED");
break;
case "RestartSerivcesForSystemEventReceiver":
Log.i(TAG, "RestartSerivcesForSystemEventReceiver");
break;
case "android.intent.action.MEDIA_MOUNTED":
Log.i(TAG, "android.intent.action.MEDIA_MOUNTE");
break;
case "android.intent.action.MEDIA_UNMOUNTEDD":
Log.i(TAG, "android.intent.action.MEDIA_UNMOUNTEDD");
break;
case "android.intent.action.MEDIA_EJECT":
Log.i(TAG, "android.intent.action.MEDIA_EJECT");
break;
case "android.intent.action.SERVICE_STATE":
Log.i(TAG, "android.intent.action.SERVICE_STATE");
break;
}
if (action.equals(Intent.ACTION_BOOT_COMPLETED)) {
Intent ootStartIntent = new Intent(context, SplashActivity.class);
ootStartIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(ootStartIntent);
}
if (intent.getAction().equals(Intent.ACTION_PACKAGE_REPLACED)) {
Intent localIntent = new Intent(context, SplashActivity.class);
localIntent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(localIntent);
}
}
}
注册广播, 其实我这里注册了N多广播,包括APP 开机自启
<receiver
android:name=".SystemEventReceiver"
android:permission="android.permission.RECEIVE_BOOT_COMPLETED">
<intent-filter>
<action android:name="android.intent.action.BOOT_COMPLETED" />
</intent-filter>
<intent-filter>
<action android:name="RestartSerivcesForSystemEventReceiver" />
</intent-filter>
<intent-filter>
<action android:name="wits.action.reboot" />
</intent-filter>
<intent-filter>
<action android:name="wits.action.shutdown" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.SERVICE_STATE" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.MEDIA_MOUNTED" />
<action android:name="android.intent.action.MEDIA_UNMOUNTED" />
<action android:name="android.intent.action.MEDIA_EJECT" />
<data android:scheme="file" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.PACKAGE_ADDED" /> <!-- add -->
<action android:name="android.intent.action.PACKAGE_REPLACED" /> <!-- update -->
<action android:name="android.intent.action.PACKAGE_REMOVED" /> <!-- delete -->
<action android:name="android.intent.action.PACKAGE_RESTARTED" /> <!-- restart -->
<action android:name="android.intent.action.BOOT_COMPLETED" /> <!-- completed -->
<data android:scheme="package" />
</intent-filter>
</receiver>
我的思路是, 抓软件崩溃,然后自动重启。因为我们可以理解静默安装后,不自动重启,可能是出现了BUG, 导致异常了。
public class RestartAPPTool {
/***重启整个APP*/
public static void restartAPP(Context context) {
restartAPP(context, 3000);
}
/**
* 重启整个APP
*
* @param context
* @param Delayed 延迟多少毫秒
*/
public static void restartAPP(Context context, long Delayed) {
/**开启一个新的服务,用来重启本APP*/
Log.i("RestartAPPTool", "27");
Intent intent = new Intent(context, KillSelfService.class);
intent.putExtra("PackageName", context.getPackageName());
intent.putExtra("Delayed", Delayed);
context.startService(intent);
/**杀死整个进程**/
android.os.Process.killProcess(android.os.Process.myPid());
// System.exit(1);
}
}
public class KillSelfService extends Service {
/**
* 关闭应用后多久重新启动
*/
private static long stopDelayed = 3000;
private String PackageName = "com.winspread.adscreenplayer";
private Handler handler;
public KillSelfService() {
Log.i("KillSelfService", "21");
handler = new Handler();
}
@Override
public int onStartCommand(final Intent intent, int flags, int startId) {
Log.i("KillSelfService", "26");
if (intent != null) {
stopDelayed = intent.getLongExtra("Delayed", 3000);
PackageName = intent.getStringExtra("PackageName");
}
handler.postDelayed(() -> {
Log.i("KillSelfService", "30");
Intent LaunchIntent = getPackageManager().getLaunchIntentForPackage(PackageName);
startActivity(LaunchIntent);
KillSelfService.this.stopSelf();
Log.i("KillSelfService", "34");
}, stopDelayed);
return super.onStartCommand(intent, flags, startId);
}
@Override
public IBinder onBind(Intent intent) {
return null;
}
}
<service android:name=".server.KillSelfService" />
public class CrashHandler implements Thread.UncaughtExceptionHandler {
/**
* The constant TAG.
*/
public static final String TAG = "CrashHandler";
// CrashHandler 实例
private static CrashHandler INSTANCE = new CrashHandler();
// 程序的 Context 对象
private Context mContext;
// 系统默认的 UncaughtException 处理类
private Thread.UncaughtExceptionHandler mDefaultHandler;
// 用来存储设备信息和异常信息
private Map<String, String> infos = new HashMap<String, String>();
// 用于格式化日期,作为日志文件名的一部分
private DateFormat formatter = new SimpleDateFormat("yyyy-MM-dd-HH-mm-ss");
/**
* 保证只有一个 CrashHandler 实例
*/
private CrashHandler() {
}
/**
* 获取 CrashHandler 实例 ,单例模式
*
* @return the instance
*/
public static CrashHandler getInstance() {
return INSTANCE;
}
/**
* 初始化
*
* @param context the context
*/
public void init(Context context) {
mContext = context;
// 获取系统默认的 UncaughtException 处理器
mDefaultHandler = Thread.getDefaultUncaughtExceptionHandler();
// 设置该 CrashHandler 为程序的默认处理器
Thread.setDefaultUncaughtExceptionHandler(this);
}
/**
* 当 UncaughtException 发生时会转入该函数来处理
*/
@Override
public void uncaughtException(Thread thread, Throwable ex) {
if (!handleException(ex) && mDefaultHandler != null) {
// 如果用户没有处理则让系统默认的异常处理器来处理
mDefaultHandler.uncaughtException(thread, ex);
} else {
RestartAPPTool.restartAPP(mContext);
}
}
/**
* 自定义错误处理,收集错误信息,发送错误报告等操作均在此完成
*
* @param ex
* @return true:如果处理了该异常信息;否则返回 false
*/
private boolean handleException(Throwable ex) {
if (ex == null) {
return false;
}
// 使用 Toast 来显示异常信息
new Thread() {
@Override
public void run() {
Looper.prepare();
Toast.makeText(mContext, "异常退出", Toast.LENGTH_LONG).show();
Looper.loop();
}
}.start();
return true;
}
}
if (!BuildConfig.DEBUG) {
CrashHandler crashHandler = CrashHandler.getInstance();
crashHandler.init(this);
}