app程序守護方案之一
阿新 • • 發佈:2018-12-10
APP保活的工作,估計開發人員都有遇到過 ,也肯定有很多套方案 ,但是隨著android的系統版本越來越高,許可權越來越嚴的情況下 ,保活越來越不好做了,
1:有人用兩個service相互吊起,但是殺程序之後,程式也是起不來了
2:有人用一畫素通知欄保活,殺程序之後也起不來的
3:使用兩個App相互吊起,嗯,這個比較靠譜 ,但是如何安裝兩個App呢,不顯示圖示的那種 ,今天我要說的就是這一種
先看截圖:
這裡我用的就是兩個APP來相互保活 ,哈哈 ,把ETV守護,內建到app裡面。意思就是 ,ETV守護,是系統APP,使用者無法刪除的 ,這裡就有一個侷限性,板卡需要root許可權,不然沒辦法實現,
需要保活的原因有很多這裡不過多解釋,這裡只說思路和程式碼:
1:APP啟動,去檢查當前守護APP有沒有安裝,如果有安裝的話,直接啟動守護程序Service,當然了,守護APP會監聽開機啟動,會自動開啟自己 ,
2:守護APP會定時檢查需要守護的APP是否在前臺 ,如果不在前臺的話,直接吊起來,別問為什麼,這是信發系統 ,就是需要這樣的牛虻。這個時間可以同過AIDL兩個介面,供外部程式設定和獲取間隔時間。
3:接下來看看程式碼 ,我做一定的解釋 :先講contral工具類
這裡會去判斷,如果已經安裝就不處理,沒有安裝的話,先把RAW的檔案,寫入本地 ,寫入成功使用adb命令把守護APK push到system/app下面。詳情見程式碼
package com.etv.util.guardian; import android.content.Context; import android.content.Intent; import android.util.Log; import com.etv.R; import com.etv.config.AppInfo; import com.etv.http.FileWriteRunnable; import com.etv.util.APKUtil; import com.etv.util.MyLog; import com.etv.util.RootCmd; /** * 安裝守護程序方法 */ public class InstallGuardianUtil { Context context; public InstallGuardianUtil(Context context) { this.context = context; } public void startInstallGuardian() { boolean isApkInstall = APKUtil.ApkState(context, AppInfo.GUARDIAN_PACKAGE_NAME); if (isApkInstall) { MyLog.i("cdl", "==程式已經安裝==="); return; } boolean isRoot = RootCmd.haveRoot(); if (!isRoot) { MyLog.i("cdl", "==裝置沒有許可權==="); return; } int rourseId = getResourceId(); String savePath = AppInfo.BASE_APK + "/" + AppInfo.GUARDIAN_APP_NAME; FileWriteRunnable runnable = new FileWriteRunnable(context, rourseId, savePath, AppInfo.GUARDIAN_APK_LENGTH, new FileWriteRunnable.WriteSdListener() { @Override public void writeProgress(int progress) { Log.e("cdl", "===progress===" + progress); } @Override public void writeSuccess(String savePath) { MyLog.i("cdl", "suucess==" + savePath); RootCmd.writeFileToSystemApp(savePath, "/system/app/guardian.apk"); } @Override public void writrFailed(String errorDesc) { Log.e("cdl", "writrFailed==" + errorDesc); } }); Thread thread = new Thread(runnable); thread.start(); } private int getResourceId() { int rourseId = R.raw.guardian; // try { // MobileInfoEntity mobileInfoEntity = CpuModel.getInfo(context); // Log.i("cdl", "品牌:" + mobileInfoEntity.getMyBrand() + "型號:" + mobileInfoEntity.getMyBrandType()); // String cpuModel = mobileInfoEntity.getMyBrandType(); // if (cpuModel.contains("3368")) { // rourseId = R.raw.guardian3368; // } // } catch (Exception e) { // } return rourseId; } /*** * 啟動守護程序 * @param contextOnly */ public static void startGuardianService(Context contextOnly) { try { boolean isApkInstall = APKUtil.ApkState(contextOnly, AppInfo.GUARDIAN_PACKAGE_NAME); if (!isApkInstall) { return; } Intent intent = new Intent(); intent.setAction("com.guardian.service.GuardianService"); //應用在清淡檔案中註冊的action intent.setPackage(AppInfo.GUARDIAN_PACKAGE_NAME); //應用程式的包名 contextOnly.startService(intent); } catch (Exception e) { } } }
將raw中apk寫入到SDCARD中
package com.etv.http; import android.content.Context; import android.os.Handler; import android.util.Log; import com.etv.util.FileUtil; import java.io.ByteArrayOutputStream; import java.io.File; import java.io.FileOutputStream; import java.io.InputStream; public class FileWriteRunnable implements Runnable { int rawId; String savePath; long fileLength; WriteSdListener listener; Context context; Handler handler = new Handler(); public FileWriteRunnable(Context context, int rawId, String savePath, long fileLength, WriteSdListener listener) { this.context = context; this.rawId = rawId; this.savePath = savePath; this.fileLength = fileLength; this.listener = listener; } @Override public void run() { try { FileUtil.creatPathNotExcit(); File fileSave = new File(savePath); if (fileSave.exists()) { // long fileSaveLength = fileSave.length(); // if (Math.abs(fileLength - fileSaveLength) < 10240) { //如果檔案記憶體滿足調教的話 // Log.i("cdl", "=========檔案合法 ,直接去播放就好了==================="); // backSuccess(savePath); // return; // } // Log.i("cdl", "=========檔案不合法 刪除檔案==================="); fileSave.delete(); } fileSave.createNewFile(); Log.i("cdl", "=========開始寫入==================="); InputStream inStream = context.getResources().openRawResource(rawId); FileOutputStream fileOutputStream = new FileOutputStream(fileSave); byte[] buffer = new byte[1024]; ByteArrayOutputStream outStream = new ByteArrayOutputStream(); int len = 0; long sum = 0; while ((len = inStream.read(buffer)) != -1) { outStream.write(buffer, 0, len); sum += len; int progress = (int) (sum * 100 / fileLength); backProgress(progress); } byte[] bs = outStream.toByteArray(); fileOutputStream.write(bs); outStream.close(); inStream.close(); fileOutputStream.flush(); fileOutputStream.close(); backSuccess(savePath); Log.i("cdl", "=========寫入完畢==================="); } catch (Exception e) { backFailed(e.toString()); Log.i("cdl", "=========寫入異常===================" + e.toString()); } } public void backFailed(final String rrorDesc) { handler.post(new Runnable() { @Override public void run() { listener.writrFailed(rrorDesc); } }); } public void backSuccess(final String filePath) { handler.post(new Runnable() { @Override public void run() { listener.writeSuccess(filePath); } }); } public void backProgress(final int prgress) { handler.post(new Runnable() { @Override public void run() { Log.i("cdl", "=========寫入中===================" + prgress); listener.writeProgress(prgress); } }); } /*** * 讀寫檔案監聽 */ public interface WriteSdListener { void writeProgress(int progress); void writeSuccess(String savePath); void writrFailed(String errorDesc); } }
接下來就是pushAPK到ystem/app中了
package com.etv.util; import android.util.Log; import java.io.DataOutputStream; import java.io.IOException; public class RootCmd { private static boolean mHaveRoot = false; /*** * 判斷當前裝置有沒有許可權 * @return */ public static boolean haveRoot() { if (!mHaveRoot) { int ret = execRootCmdSilent("echo test"); // 通過執行測試命令來檢測 if (ret != -1) { mHaveRoot = true; } else { } } else { } return mHaveRoot; } // 執行命令但不關注結果輸出 public static int execRootCmdSilent(String cmd) { int result = -1; DataOutputStream dos = null; try { Process p = Runtime.getRuntime().exec("su"); dos = new DataOutputStream(p.getOutputStream()); dos.writeBytes(cmd + "\n"); dos.flush(); dos.writeBytes("exit\n"); dos.flush(); p.waitFor(); result = p.exitValue(); } catch (Exception e) { e.printStackTrace(); } finally { if (dos != null) { try { dos.close(); } catch (IOException e) { e.printStackTrace(); } } } return result; } /*** * @param command * @return */ public static boolean exusecmd(String command) { Log.e("cdl", "===========" + 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(); Log.e("cdl", "======000==writeSuccess======"); process.waitFor(); } catch (Exception e) { Log.e("cdl", "======111=writeError======" + e.toString()); return false; } finally { try { if (os != null) { os.close(); } if (process != null) { process.destroy(); } } catch (Exception e) { e.printStackTrace(); } } return true; } // RootCmd.writeFileToSystem(srcfile.getPath(), "/system/media/bootanimation.zip"); public static void writeFileToSystem(String filePath, String sysFilePath) { exusecmd("mount -o rw,remount /system"); exusecmd("rm -rf /system/media/boomAnimal.zip"); exusecmd("chmod 777 /system/media"); exusecmd("cp " + filePath + " " + sysFilePath); } public static void writeFileToSystemApp(String filePath, String sysFilePath) { exusecmd("mount -o rw,remount /system"); exusecmd("rm -rf /system/app/guardian.apk"); exusecmd("cp " + filePath + " " + sysFilePath); exusecmd("chmod 777 /system/app/guardian.apk"); } }
然後重啟電腦,之後你想怎麼保活直接在保活app中處理就好了,這裡只將思路.