Android 版本更新的業(yè)務(wù)邏輯分析

版本更新邏輯

1赁还、聯(lián)網(wǎng)妖泄,從遠(yuǎn)程服務(wù)器獲取最新的版本,然后跟本地的版本號比對艘策,如果遠(yuǎn)程的版本號大于本地的版本號蹈胡,彈出對話框,有新版本朋蔫,如果相等罚渐,已經(jīng)是最新版本,不需要更新驯妄,本地版本號不可能比遠(yuǎn)程版本好大荷并,

1、立刻升級
點(diǎn)擊立刻升級青扔,把最新的apk下載下來源织,然后提示更新安裝。
2微猖、稍后再說
點(diǎn)擊稍后再說谈息,立即進(jìn)入主界面。

3凛剥、版本名侠仇、版本號
1、versionCode:給程序員看的
2、versionName:給用戶看的
3逻炊、版本名規(guī)則:eg互亮。6.1.3
1、6.1.C:小版本更新余素,修改了小bug豹休,做一些微調(diào)
2、6.B.3:中等版本更新桨吊,更改了比較重要的bug慕爬,添加新功能
3、A.1.3:大版本更新屏积,很重要的更新医窿,里程碑意義的更新。

實(shí)戰(zhàn)
D:\Software-tools\Tomcat\webapps\ROOT\update.txt
里面新建文本update模擬遠(yuǎn)程版本炊林,在update文本里面寫上json格式的數(shù)據(jù):

{"remoteVesion":"2"}  //版本號為:2

訪問成功:


異常處理的原則

1姥卢、如果有統(tǒng)一的解決方案,就在方法內(nèi)部try catch掉
2渣聚、如果每次調(diào)用處理異常的方式都不同独榴,就直接往外拋(誰調(diào)用,誰處理)

版本更新demo

SplashActivity

public class SplashActivity extends Activity {

    private static final String TAG = "SplashActivity";
    
    private static final int REQUEST_CODE = 100;
    //錯(cuò)誤碼
    protected static final int NET_ERROR = 1001;

    protected static final int NET_KEEP = 1002;
    
    private TextView tv_version;
    private ProgressDialog progressDialog;
    
    Handler mHandler = new Handler(){
        public void handleMessage(android.os.Message msg) {
            switch (msg.what) {
            case NET_ERROR:
                Toast.makeText(getApplicationContext(), "網(wǎng)絡(luò)錯(cuò)誤奕枝!", Toast.LENGTH_SHORT).show();
                enterHome();
                break;
            case NET_KEEP:
                Toast.makeText(getApplicationContext(), "服務(wù)器正在維護(hù)棺榔!", Toast.LENGTH_SHORT).show();
                enterHome();
                break;

            default:
                break;
            }
            
        };
    };
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_splash);

        tv_version = (TextView) findViewById(R.id.splash_tv_version);
        // 設(shè)置版本名
        initVersionName();
        //版本更新
        updateVersion();
    }

    private void updateVersion() {
        final String url = "http://192.168.39.50:8080/update.txt";
        //1.訪問服務(wù)器,獲取最新版本信息
        new Thread(new Runnable() {
            
            @Override
            public void run() {
                 //01. 定義okhttp
//              OkHttpClient okHttpClient_get = new OkHttpClient();
                //設(shè)置連接超時(shí)時(shí)間
                OkHttpClient okHttpClient_get = new OkHttpClient.Builder().connectTimeout(3, TimeUnit.SECONDS).build();
                //02.請求體
                Request request = new Request.Builder()
                    .get()//get請求方式
                    .url(url)//網(wǎng)址
                    .build();
                    
                //03.執(zhí)行okhttp
                Response response;
                try {
                    response = okHttpClient_get.newCall(request).execute();
                    
                    /**
                     * 打印數(shù)據(jù),注意一次請求隘道,一次響應(yīng)症歇,讀取一次就沒了,要注釋掉
                     */
//                  System.out.println(response.body().string());
                    String json = response.body().string();
                    //001.解析
                    //{"remoteVesion":"2","desc":"1.添加了搖一搖的功能\n2.優(yōu)化了用戶的體驗(yàn)","apkUrl":"http://192.168.39.50:8080/safenet.apk"}
                    JSONObject jsonObject = new JSONObject(json);
                    
                    int remoteVesion = jsonObject.getInt("remoteVesion");
                    String desc = jsonObject.getString("desc");
                    String url = jsonObject.getString("apkUrl");
                    
                    final UpdateInfo updateInfo = new UpdateInfo();
                    updateInfo.remoteVesion = remoteVesion;
                    updateInfo.desc = desc;
                    updateInfo.apkUrl = url;
                    
                    //2.判斷最新版本與本地是否一致
                    int localVersion = PackageUtil.getVersionCode(getApplicationContext());
                    if (remoteVesion > localVersion) {
                        //3.彈出提示dialog
                        //不能在子線程中更新UI
                        runOnUiThread(new Runnable() {
                            
                            @Override
                            public void run() {
                                showUpdateDialog(updateInfo);
                            }
                        });
                        
                    }else{
                        //跳轉(zhuǎn)到主頁 
                        enterHome();
                    }
                } catch (IOException e) {
                    Message message = mHandler.obtainMessage();
                    message.what = NET_ERROR;
                    message.sendToTarget();
                    
                    e.printStackTrace();
                } catch (JSONException e) {
                    Message message = mHandler.obtainMessage();
                    message.what = NET_KEEP;
                    message.sendToTarget();
                    
                    e.printStackTrace();
                }
                
            }
        }).start();
        
    }
    //進(jìn)入主頁
    protected void enterHome() {
        mHandler.postDelayed(new Runnable() {
            
            @Override
            public void run() {
                Intent intent = new Intent(SplashActivity.this, HomeActivity.class);
                startActivity(intent);  
            }
        }, 2000);
        
    }

    private void showUpdateDialog(final UpdateInfo info) {
        AlertDialog.Builder builder = new Builder(SplashActivity.this);
        builder.setTitle("版本更新提示");
        builder.setCancelable(false);//點(diǎn)擊旁邊不能消失
        builder.setMessage(info.desc);
        
        //4.是否升級
        builder.setPositiveButton("立刻升級", new OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                
                downApk(info);
            }
        });
        builder.setNegativeButton("稍后再說", new OnClickListener() {
            
            @Override
            public void onClick(DialogInterface dialog, int which) {
                //回到主頁
                enterHome();
                
            }
        });
        builder.show();
    }

    protected void downApk(UpdateInfo info) {
        //5.下載最新APK
        if (Environment.getExternalStorageState().equals(Environment.MEDIA_MOUNTED)) {
            
            progressDialog = new ProgressDialog(this);
            progressDialog.setCancelable(false);
            progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
            progressDialog.show();
            
            new Thread(new DownTask(info.apkUrl)).start();
        }else{
            //回到主頁
            Toast.makeText(this, "沒有SD卡谭梗!", Toast.LENGTH_SHORT).show();
            enterHome();
        }
    
    }
    
    class DownTask implements Runnable{
        
        String mUrl;
        
        public DownTask(String apkUrl) {
            this.mUrl = apkUrl;
        }

        @Override
        public void run() {
            InputStream is = null;
            FileOutputStream fos = null;
            try {
                Response response = HttpUtil.get(mUrl);
                is = response.body().byteStream();
                
                long contentLength = response.body().contentLength();
                //01.設(shè)置進(jìn)度條最大值
                progressDialog.setMax((int) contentLength);
                //路徑:mnt/sdcard/
                File file = new File(Environment.getExternalStorageDirectory(), "safe.apk");
                fos = new FileOutputStream(file);
                
                byte[] buffer = new byte[1024];
                
                int len = -1;
                
                int progress = 0;
                while((len = is.read(buffer)) != -1){
                    fos.write(buffer, 0, len);
                    
//                  SystemClock.sleep(10);
                    progress += len;
                    //02.設(shè)置進(jìn)度
                    progressDialog.setProgress(progress);
                }
                
                fos.flush();
                //03.進(jìn)度條消失
                progressDialog.dismiss();
                //6.提示用戶安裝 
                installApk(file);
            } catch (IOException e) {
                Message message = mHandler.obtainMessage();
                message.what = NET_ERROR;
                message.sendToTarget();
                e.printStackTrace();
            } finally{
                closeIo(fos);
                closeIo(is);
//              closeIo2(fos,is);
            }
        }
        
    }
    
    public void closeIo(Closeable io){
        if (io != null) {
            try {
                io.close();
                io = null;
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    
    public void installApk(File file) {
//       <intent-filter>
//         <action android:name="android.intent.action.VIEW" />
//         <category android:name="android.intent.category.DEFAULT" />
//         <data android:scheme="content" />
//         <data android:scheme="file" />
//         <data android:mimeType="application/vnd.android.package-archive" />
//     </intent-filter>
        //7.安裝APK
        Intent intent = new Intent();
        intent.addCategory("android.intent.category.DEFAULT");
        intent.setAction("android.intent.action.VIEW");
        //獲取文件的uri
        Uri data = Uri.fromFile(file);
        intent.setDataAndType(data, "application/vnd.android.package-archive");
//      startActivity(intent);
        startActivityForResult(intent, REQUEST_CODE);
        
    }
    
    @Override
    protected void onActivityResult(int requestCode, int resultCode, Intent data) {
        super.onActivityResult(requestCode, resultCode, data);
        if (requestCode == REQUEST_CODE) {
            //系統(tǒng)默認(rèn)的用戶行為只有兩種:yes no
            switch (resultCode) {
            case Activity.RESULT_OK:
                //***被覆蓋安裝了忘晤,所以不會(huì)出日志
                Log.d(TAG, "RESULT_OK");
                break;
            case Activity.RESULT_CANCELED:
                Log.d(TAG, "RESULT_CANCELED");
                //進(jìn)入到主頁
                enterHome();
                break;

            default:
                break;
            }
            
        }
    }

    public void closeIo2(Closeable... io){
        for (int i = 0; i < io.length; i++) {
            if(io[i] != null){
                try {
                    io[i].close();
                    io[i] = null;
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
    }

    private void initVersionName() {

        // PackageManager pm = this.getPackageManager();
        // /**
        // * flags:標(biāo)志位,0標(biāo)志包的基本信息
        // */
        // try {
        // PackageInfo info = pm.getPackageInfo(getPackageName(), 0);
        // String versionName = info.versionName;
        //
        // tv_version.setText(versionName);
        // } catch (NameNotFoundException e) {
        // e.printStackTrace();
        // }
        
        String versionName = PackageUtil.getVersionName(this);
        tv_version.setText(versionName);

    }
}

UpdateInfo



public class UpdateInfo {
    
    public int remoteVesion;//遠(yuǎn)程版本號
    public String desc;//版本描述
    public String apkUrl;//apk的下載地址
}

HttpUtil

public class HttpUtil {
    
    public static Response get(String url) throws IOException{
         //01. 定義okhttp
        OkHttpClient okHttpClient_get = new OkHttpClient();
        //02.請求體
        Request request = new Request.Builder()
            .get()//get請求方式
            .url(url)//網(wǎng)址
            .build();
            
        //03.執(zhí)行okhttp
        Response response = okHttpClient_get.newCall(request).execute();
        
        return response;
    }       
}


public class PackageUtil {
    
    public static String getVersionName(Context context){
        
        PackageManager pm = context.getPackageManager();
        /**
         * flags:標(biāo)志位激捏,0標(biāo)志包的基本信息
         */
        try {
            PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
            String versionName = info.versionName;
            return versionName;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return "未知版本名";
    }
    
    public static int getVersionCode(Context context){
        
        PackageManager pm = context.getPackageManager();
        /**
         * flags:標(biāo)志位设塔,0標(biāo)志包的基本信息
         */
        try {
            PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
            int versionCode = info.versionCode;
            
            return versionCode;
        } catch (NameNotFoundException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        return 1;
    }
}

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市远舅,隨后出現(xiàn)的幾起案子闰蛔,更是在濱河造成了極大的恐慌,老刑警劉巖图柏,帶你破解...
    沈念sama閱讀 221,576評論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件序六,死亡現(xiàn)場離奇詭異,居然都是意外死亡爆办,警方通過查閱死者的電腦和手機(jī)难咕,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評論 3 399
  • 文/潘曉璐 我一進(jìn)店門课梳,熙熙樓的掌柜王于貴愁眉苦臉地迎上來距辆,“玉大人余佃,你說我怎么就攤上這事】缢悖” “怎么了爆土?”我有些...
    開封第一講書人閱讀 168,017評論 0 360
  • 文/不壞的土叔 我叫張陵,是天一觀的道長诸蚕。 經(jīng)常有香客問我步势,道長,這世上最難降的妖魔是什么背犯? 我笑而不...
    開封第一講書人閱讀 59,626評論 1 296
  • 正文 為了忘掉前任坏瘩,我火速辦了婚禮,結(jié)果婚禮上漠魏,老公的妹妹穿的比我還像新娘倔矾。我一直安慰自己,他們只是感情好柱锹,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評論 6 397
  • 文/花漫 我一把揭開白布哪自。 她就那樣靜靜地躺著,像睡著了一般禁熏。 火紅的嫁衣襯著肌膚如雪壤巷。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 52,255評論 1 308
  • 那天瞧毙,我揣著相機(jī)與錄音胧华,去河邊找鬼。 笑死宙彪,一個(gè)胖子當(dāng)著我的面吹牛撑柔,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播您访,決...
    沈念sama閱讀 40,825評論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼铅忿,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了灵汪?” 一聲冷哼從身側(cè)響起檀训,我...
    開封第一講書人閱讀 39,729評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎享言,沒想到半個(gè)月后峻凫,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,271評論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡览露,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評論 3 340
  • 正文 我和宋清朗相戀三年荧琼,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡命锄,死狀恐怖堰乔,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情脐恩,我是刑警寧澤镐侯,帶...
    沈念sama閱讀 36,183評論 5 350
  • 正文 年R本政府宣布,位于F島的核電站驶冒,受9級特大地震影響苟翻,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜骗污,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評論 3 333
  • 文/蒙蒙 一崇猫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧需忿,春花似錦邓尤、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至擅这,卻和暖如春澈魄,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背仲翎。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評論 1 272
  • 我被黑心中介騙來泰國打工痹扇, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人溯香。 一個(gè)月前我還...
    沈念sama閱讀 48,906評論 3 376
  • 正文 我出身青樓鲫构,卻偏偏與公主長得像,于是被迫代替她去往敵國和親玫坛。 傳聞我的和親對象是個(gè)殘疾皇子结笨,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評論 2 359

推薦閱讀更多精彩內(nèi)容

  • Spring Cloud為開發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)湿镀,斷路器炕吸,智...
    卡卡羅2017閱讀 134,697評論 18 139
  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 172,283評論 25 707
  • 因?yàn)橐Y(jié)局swift3.0中引用snapKit的問題,看到一篇介紹Xcode8,swift3變化的文章,覺得很詳細(xì)...
    uniapp閱讀 4,422評論 0 12
  • 昨天注冊了賬號通過Paypal充了50刀, 上了三個(gè)campaign, 都是聯(lián)盟am推薦的勉痴, 兩個(gè)adult, 一...
    asilentwolf閱讀 1,858評論 0 0
  • 是否蒸矛,曾在一段旅途中瀑罗, 遇到過那么一個(gè)人胸嘴, 曾為你解過惑 無關(guān)風(fēng)花,無關(guān)雪月 老板斩祭,您這有抗過敏的藥膏嗎劣像? 正在吧...
    三三張閱讀 264評論 0 1