1. 程式人生 > >app程序守護方案之一

app程序守護方案之一

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中處理就好了,這裡只將思路.