實現apk的下載安裝與啓動

前言:公司最近做了一個項目,一套放在路邊的廣告牌系統,出現問題後不可能實現人工的服務,所以需要從下載到安裝到啓動都需要系統自己操作,這樣就無疑給我帶來了巨大的困難,不過俗話說得好:沒有困難製造困難也要上,哈哈 好了廢話不多說了,直接上代碼。
1.文件下載與靜默安裝

public class UpdateActivity extends AppCompatActivity {
    /**
     * 0 開始下載
     * 1.正在下載
     * 2.下載完成
     */
    private static final int SHOWDOWNLOADDIALOG = 0;
    private static final int UPDATEDOWNLOADDIALOG = 1;
    private static final int DOWNLOADFINISHED = 2;
    //軟件下載地址
    private String url = "http://ystel.rrtel.com/garbage/interface.php?action=apkDownload";
    //軟件下載路徑
    private String rootPath = Environment.getExternalStorageDirectory() + "/androidsolution/download/";
    //軟件下載保存的名稱
    private String fileName = "update.apk";
    private DecimalFormat df = new DecimalFormat("#0.00");//設置結果保留兩位小數
    private ProgressBar pb;
    //顯示軟件下載進度
    private TextView textView;
    private int fileLength;
    //靜默安裝命令
    private String cmd_install = "pm install -r ";

    /**
     * 安裝
     */

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                case SHOWDOWNLOADDIALOG://顯示正在下載的對話框
                    pb.setMax(fileLength);
                    break;
                case UPDATEDOWNLOADDIALOG://刷新正在下載對話框的內容
                    int curSize = (int) msg.obj;
                    pb.setProgress(curSize);
                    textView.setText(df.format((float) curSize / (float) fileLength * 100) + "%");
                    break;
                case DOWNLOADFINISHED://下載完成後進行的操作
                    ToastUtils.showLongToastSafe(UpdateActivity.this, "系統正在重新安裝啓動,請勿操作");
                    Log.e("tag", hasRootPerssion() + "");
                    if (hasRootPerssion()) {
                        String cmd = cmd_install + rootPath + fileName;
                        Log.e("tag", "靜默安裝:" + excuteSuCMD(cmd));
                    } else {
                        Log.e("tag", "無權限");
                    }
                    break;
                default:
                    break;

            }
        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_update);
        pb = (ProgressBar) findViewById(R.id.progress);
        textView = (TextView) findViewById(R.id.tv);
        /**
         * 開啓一個線程進行軟件下載
         */
        new Thread(new Runnable() {
            @Override
            public void run() {
                downLoadFile(url);
            }
        }).start();

    }

    //執行shell命令
    protected int excuteSuCMD(String cmd) {
        try {
            final Process process = Runtime.getRuntime().exec("su");
            DataOutputStream dos = new DataOutputStream(
                    (OutputStream) process.getOutputStream());
            // 部分手機Root之後Library path 丟失,導入library path可解決該問題
            dos.writeBytes((String) "export LD_LIBRARY_PATH=/vendor/lib:/system/lib\n");
            cmd = String.valueOf(cmd);
            dos.writeBytes((String) (cmd + "\n"));
            dos.flush();
            dos.writeBytes("exit\n");
            dos.flush();
            return 0;
        } catch (Exception localException) {
            Log.e("tag", localException.getMessage());
            localException.printStackTrace();
            return -1;
        }
    }


    /**
     * 判斷手機是否有root權限
     */
    public static boolean hasRootPerssion() {
        PrintWriter PrintWriter = null;
        Process process = null;
        try {
            process = Runtime.getRuntime().exec("su");
            PrintWriter = new PrintWriter(process.getOutputStream());
            PrintWriter.flush();
            PrintWriter.close();
            return true;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (process != null) {
                process.destroy();
            }
        }
        return false;
    }


    //下載apk程序代碼
    protected void downLoadFile(String httpUrl) {
        // TODO Auto-generated method stub

        InputStream inputStream = null;
        FileOutputStream fileOutputStream = null;
        File tmpFile = new File(rootPath);
        if (!tmpFile.exists()) {
            tmpFile.mkdir();
        }
        final File file = new File(rootPath + fileName);

        try {
            URL url = new URL(httpUrl);
            HttpURLConnection conn = (HttpURLConnection) url
                    .openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            if (conn.getResponseCode() == 200) {
                //獲得文件的長度
                fileLength = conn.getContentLength();
                inputStream = conn.getInputStream();
                fileOutputStream = new FileOutputStream(file);
                //子線程不能顯示和刷新UI
                Message msg = Message.obtain();
                msg.what = SHOWDOWNLOADDIALOG;
                handler.sendMessage(msg);
                byte[] buffer = new byte[1024 * 2];
                int length = 0;

                while ((length = inputStream.read(buffer)) != -1) {
                    fileOutputStream.write(buffer, 0, length);
                    int curlength = (int) file.length();
                    Message updateMsg = Message.obtain();
                    updateMsg.what = UPDATEDOWNLOADDIALOG;
                    updateMsg.obj = curlength;
                    handler.sendMessage(updateMsg);
                }

                if (file.length() == fileLength) {
                    //下載完成
                    Message finishedMsg = Message.obtain();
                    finishedMsg.what = DOWNLOADFINISHED;
                    finishedMsg.obj = file;
                    handler.sendMessage(finishedMsg);
                }
            } else {
                Toast.makeText(UpdateActivity.this, "連接超時", Toast.LENGTH_SHORT)
                        .show();
            }
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        } finally {
            try {
                if (fileOutputStream != null) {
                    fileOutputStream.flush();
                    fileOutputStream.close();
                }
                if (inputStream != null) {
                    inputStream.close();
                }
            } catch (Exception e) {

            }
        }
    }

}

註釋:判斷軟件是否有更新的代碼就不貼出來了,這裏主要是軟件的下載、下載後自動安裝。關於自動安裝我看了很多資料,不過大多數都是用shell命令來執行的,命令是:pm install -r (文件路徑)。但是必須要保證設備已經root,不root的設備是無法靜默安裝的。
2.安裝後自啓:新建UpdateBroadcast 繼承BroadcastReceiver

public class UpdateBroadcast extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        if (intent.getAction().equals("android.intent.action.PACKAGE_REPLACED")) {
            String packageName = intent.getDataString();
            Log.e("tag", "安裝了:" + packageName + "包名的程序");
            Intent intent2 = new Intent(context, FirstActivity.class);
            intent2.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            context.startActivity(intent2);
        }
    }
}

在AndroidManifest.xml文件中註冊廣播

 <receiver android:name=".broadcast.UpdateBroadcast">
            <intent-filter>
                <!-- 軟件更新廣播 -->
                <action android:name="android.intent.action.PACKAGE_REPLACED" />
                <data android:scheme="package" />

            </intent-filter>
        </receiver>

註釋:這裏的思路是用廣播監聽軟件的更新,當有軟件更新後可以在onReceive中獲取到包名,根據包名判斷是不是自己的軟件更新了,從而進行重啓操作。(最重要的一點是:在服務器上的apk必須有廣播監聽功能,否則是不能實現更新軟件後自啓的)

荊軻刺秦王!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章