1. 程式人生 > >Android實現版本更新和自動安裝

Android實現版本更新和自動安裝

直接執行的專案和打包的專案apk簽名不同,所以不能直接用開發工具執行專案進行版本更新.需要用apk打包安裝的形式更新,否則會提示"簽名衝突",無法完成覆蓋安裝


/**	版本更新	*/
public class SplashActivity extends Activity {

    private static final String TAG = "SplashActivity";
    public static final int SHOW_UPDATE_DIALOG = 0;
    public static final int SHOW_ERROR = 1;
    public final static int CONNECT_TIMEOUT = 5000;
    public final static int READ_TIMEOUT = 5000;
    public final static int WRITE_TIMEOUT = 5000;

    //獲取裝置名稱
    private String deviceName = Build.MODEL;
    //獲取裝置序列號
    private String serialNumber = getSerialNumber();
    private VersionDataBean versionDataBean;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        getWindow().setFlags(WindowManager.LayoutParams.FLAG_FULLSCREEN, WindowManager.LayoutParams.FLAG_LAYOUT_IN_SCREEN);
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash); 
        initData();
 }
    /**
     * 初始化資料
     */
    private void initData() {
        boolean autoUpdate = PreferenceUtils.getBoolean(this, Constants.AUTO_UPDATE, true);
        if (autoUpdate) {
            //版本更新,去伺服器獲取最新的版本,和本地版本比較
            new Thread(new CheckServerVersion()).start();
        } else {
            //直接跳轉到登入介面
            load2Login();
        }
    }

    private Handler handler = new Handler() {
        @Override
        public void handleMessage(Message msg) {
            super.handleMessage(msg);
            switch (msg.what) {
                /** 彈出提示更新的dialog   */
                case SHOW_UPDATE_DIALOG:
                    showUpdateDialog();
                    break;

                /** 提示錯誤    */
                case SHOW_ERROR:
                    Toast.makeText(SplashActivity.this, msg.obj+"", Toast.LENGTH_LONG).show();
                    load2Login();
                    break;

                default:
                    break;
            }
        }
    };

    /**
     * 檢查伺服器端版本號
     */
    private class CheckServerVersion implements Runnable {
        @Override
        public void run() {
            //訪問網路,獲取伺服器端版本號
            OkHttpClient client = new OkHttpClient.Builder().readTimeout(READ_TIMEOUT, TimeUnit.SECONDS).writeTimeout
                    (WRITE_TIMEOUT,TimeUnit.SECONDS).connectTimeout(CONNECT_TIMEOUT, TimeUnit.SECONDS).build();
            String url = new UrlInfo(SplashActivity.this).getUrl();
            if (url.equals("http://null:null")) {
                load2Login();
            } else {
                VersionDatas versionDatas = new VersionDatas();
                //物件轉json
                final Gson gson = new Gson();
                String versionDatasJson = gson.toJson(versionDatas);
                FormBody body = new FormBody.Builder().add("versionDatasJson", versionDatasJson).build();
                Request request = new Request.Builder().url(url).post(body).build();
                client.newCall(request).enqueue(new Callback() {
                    @Override
                    public void onFailure(Call call, IOException e) {
                        //如果連線超時則跳轉到登入介面
                        Message msg = Message.obtain();
                        msg.what = SHOW_ERROR;
                        msg.obj = "網路異常!請檢查網路連線狀況及設定資訊";
                        handler.sendMessage(msg);
                    }

                    @Override
                    public void onResponse(Call call, Response response) throws IOException {
                        if (response.isSuccessful()) {
                            Log.d(TAG, "訪問介面成功");
                            String json = response.body().string();
                            Log.d(TAG, "獲取伺服器端版本號json=   " + json);
                            // 解析json資料
                            if(versionDataBean!=null){
                                versionDataBean = gson.fromJson(json, VersionDataBean.class);
                                //獲取到伺服器端版本號,對比本地的版本號
                                int serverVersionCode = versionDataBean.VERSION_NO;
                                int localVersionCode = PackageUtils.getVersionCode(SplashActivity.this);
                                if (serverVersionCode > localVersionCode) {
                                    //伺服器端版本號大於本地版本號,彈出dialog提示更新
                                    Message showUpdateDialog = Message.obtain();
                                    showUpdateDialog.what = SHOW_UPDATE_DIALOG;
                                    handler.sendMessage(showUpdateDialog);
                                } else {
                                    //跳轉到登入介面
                                    load2Login();
                                }
                            }else{
                                load2Login();
                                Log.d(TAG,"versionDatabean為空0918");
                            }
                        } else {
                            //跳轉到登入介面
                            Log.d(TAG, "訪問介面失敗");
                            load2Login();
                        }
                    }
                });
            }
        }
    }

    /**
     * 彈出提示更新的dialog
     */
    private void showUpdateDialog() {
        AlertDialog.Builder dialog = new AlertDialog.Builder(this);
        dialog.setCancelable(false);
        dialog.setTitle("版本更新提示");
        dialog.setMessage("檢查到有最新版本,是否更新?");
        dialog.setNegativeButton("暫不更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //跳轉到登入介面
                load2Login();
            }
        });
        dialog.setPositiveButton("立刻更新", new DialogInterface.OnClickListener() {
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //從伺服器端下載最新apk
                downloadApk();
            }
        });
        dialog.show();
    }

    /**
     * 從伺服器端下載最新apk
     */
    private void downloadApk() {
        //顯示下載進度
        ProgressDialog dialog = new ProgressDialog(this);
        dialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        dialog.setCancelable(false);
        dialog.show();

        //訪問網路下載apk
        new Thread(new DownloadApk(dialog)).start();
    }

    /**
     * 訪問網路下載apk
     */
    private class DownloadApk implements Runnable {
        private ProgressDialog dialog;
        InputStream is;
        FileOutputStream fos;

        public DownloadApk(ProgressDialog dialog) {
            this.dialog = dialog;
        }

        @Override
        public void run() {
            OkHttpClient client = new OkHttpClient();
            String url = versionDataBean.VERSION_URL;
            Request request = new Request.Builder().get().url(url).build();
            try {
                Response response = client.newCall(request).execute();
                if (response.isSuccessful()) {
                    Log.d(TAG, "開始下載apk");
                    //獲取內容總長度
                    long contentLength = response.body().contentLength();
                    //設定最大值
                    dialog.setMax((int) contentLength);
                    //儲存到sd卡
                    File apkFile = new File(Environment.getExternalStorageDirectory(), System.currentTimeMillis() + ".apk");
                    fos = new FileOutputStream(apkFile);
                    //獲得輸入流
                    is = response.body().byteStream();
                    //定義緩衝區大小
                    byte[] bys = new byte[1024];
                    int progress = 0;
                    int len = -1;
                    while ((len = is.read(bys)) != -1) {
                        try {
                            Thread.sleep(1);
                            fos.write(bys, 0, len);
                            fos.flush();
                            progress += len;
                            //設定進度
                            dialog.setProgress(progress);
                        } catch (InterruptedException e) {
                            Message msg = Message.obtain();
                            msg.what = SHOW_ERROR;
                            msg.obj = "ERROR:10002";
                            handler.sendMessage(msg);
                            load2Login();
                        }
                    }
                    //下載完成,提示使用者安裝
                    installApk(apkFile);
                }
            } catch (IOException e) {
                Message msg = Message.obtain();
                msg.what = SHOW_ERROR;
                msg.obj = "ERROR:10003";
                handler.sendMessage(msg);
                load2Login();
            } finally {
                //關閉io流
                if (is != null) {
                    try {
                        is.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    is = null;
                }
                if (fos != null) {
                    try {
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                    fos = null;
                }
            }
            dialog.dismiss();
        }
    }

    /**
     * 下載完成,提示使用者安裝
     */
    private void installApk(File file) {
        //呼叫系統安裝程式
        Intent intent = new Intent();
        intent.setAction("android.intent.action.VIEW");
        intent.addCategory("android.intent.category.DEFAULT");
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        startActivityForResult(intent, REQUEST_INSTALL_CODE);
    }

    /**
     * 跳轉到登入介面
     */
    private void load2Login() {
        new Thread(new Runnable() {
            @Override
            public void run() {
                try {
                    Thread.sleep(2000);
                    Intent toLogin = new Intent(SplashActivity.this, LoginActivity.class);
                    startActivity(toLogin);
                    finish();
                } catch (InterruptedException e) {
                    e.printStackTrace();
                }
            }
        }).start();
    }

    /**
     * 跳轉到主介面
     */
    private void load2MainActivity() {
        Intent toMainActivity = new Intent(SplashActivity.this, MainActivity.class);
        startActivity(toMainActivity);
        finish();
    }

    /**
     * 獲取裝置序列號
     */
    private String getSerialNumber() {
        String serial = null;
        try {
            Class<?> c = Class.forName("android.os.SystemProperties");
            Method get = c.getMethod("get", String.class);
            serial = (String) get.invoke(c, "ro.serialno");
        } catch (Exception e) {
            e.printStackTrace();
        }
        return serial;
    }

    /**
     * 封裝版本升級資料
     */
    private class VersionDatas {
        String COMMAND = "GET_APP_VERSION";
        String DEVICE_NAME = deviceName;
        String DEVICE_SN = serialNumber;
    }
}
以上例項如有不足請指出.