admin管理员组

文章数量:1516870

android检查更新app是一个比较常见的功能。但是功能也比较单一。也是一块可以复用的代码。所以我这里想把自己检查更新的代码写下来。如果想使用直接移植过去就好。也不用重复开发了。

整个检查更新的大致过程

1.需要用户触发检查更新,所以界面里做个btn
2.用户点击btn后触发事件,弹出一个dialog或者toast提示用户是否是最新版本,需不需要更新
3.btn点击触发后,我们不能直接在UI层里做检查更新的操作。所以检查更新的逻辑就要开线程。这里的代码一想就是重点了吧。所以封装出来让btn onClick事件调用比较好。
4.检查更新的逻辑一般都是这样的:
第一,检查。
客户端内持有一个检查更新的url.这个url存在的目的就是为了检查是不是最新版本。一般这个url从服务端传来的内容包括:apk下载url、最新的apk版本、apk包名、apk更新信息。哈哈。是不是特别熟悉?传来的东西我们需要解析啦!那么,就要和后端的小伙伴商量定接口了吧?这里直接意淫一下,我们的接口定好了。服务器就用json提供上面说的四块儿内容。我们从url取出来就是json格式的数据了。拿回来以后直接json解析,解析完了就封装到本地的封装对象供我们使用。
既然是检查,那你拿回来最新版本的信息是不是跟本地有对比才有新旧之分?顺理成章。我们需要拿到本地的版本信息。上网查查有没有这么一个类啊?哎呦喂,果然有!就是PackageManager。好,通过它。我们有了本地的版本信息啦!下面就是一个核心而又简单的逻辑了。对比版本,if 后台版本>本地版本,那么下载后台版本(这里还不是更新呢)。else 告诉用户已经是最新版本。
第二,下载。
这一块想一想跟检查貌似以两块代码。嗯,我分开写,方便理思路。利用上面检查给的apk下载url下载到本地文件夹。下载的过程有时候需要给用户展示。所以这里用handler在ui展现一下下载过程。
第三,更新。
下载好了,剩下更新了。

MyApplication.java

这里写一个MyApplication类继承自Application,在里面获取一个全局的context,从此不再为拿不到context心烦了。

publicclassMyApplicationextendsApplication {publicstatic Context mContext;
    @OverridepublicvoidonCreate() {
        super.onCreate();
        mContext = getApplicationContext();
    }
}

manifest.xml

versionCode versionName要写出来。是用来比较版本的。这里选用versionCode比较。

<?xml version="1.0" encoding="utf-8"?><manifestxmlns:android=""package="com.zharma.updatetest"android:versionCode="1"android:versionName="1.0.0"><application
android:allowBackup="true"android:icon="@mipmap/ic_launcher"android:label="@string/app_name"android:supportsRtl="true"android:theme="@style/AppTheme"><activityandroid:name=".MainActivity"><intent-filter><actionandroid:name="android.intent.action.MAIN" /><categoryandroid:name="android.intent.category.LAUNCHER" /></intent-filter></activity></application></manifest>

布局

首先说一下最直观的,apk更新最多出现在的就是在设置之类的界面中。这些界面的布局细节就不说了。这里为了以后复用简便也不做冗余的嵌套。直接就是一个btn。

<?xml version="1.0" encoding="utf-8"?><RelativeLayoutxmlns:android=""xmlns:tools=""android:layout_width="match_parent"android:layout_height="match_parent"tools:context="com.zharma.updatetest.MainActivity"><Button
android:id="@+id/btnDownload"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="检查更新"/></RelativeLayout>

btn点击事件

publicclassMainActivityextendsActivity {private Button btnDownload;
    private View.OnClickListener listener = new View.OnClickListener() {
        @OverridepublicvoidonClick(View v) {
            switch (v.getId()) {
                case R.id.btnDownload:
                //在这里做检查业务逻辑break;
            }
        }
    };
    @OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnDownload = (Button) findViewById(R.id.btnDownload);
        btnDownload.setOnClickListener(listener);
    }
}

好了。界面搭的简陋一点能跑就行。

检查、下载、更新

检查是一个url请求,然后返回后台提供的版本json数据,用gson解析、封装到封装对象中。获取本地版本号(我们用versionCode比较版本)对比处理。
这个过程我就一起写下来。

封装类:
UpdateInfo

publicclass UpdateInfo {
    publicint versionCode;
    public String versionName;
    public String url;
    public String description;
}
/**
 * Created by dahe on 16/8/21.
 */publicclassCheckVersionimplementsRunnable{//VERSIONINFO_URL是访问服务器拿到查询更新json数据的url,一般这个是在单独的一个数据类中写的。那样的话让CheckVersion继承自那个类。拿到url来用。现在这里设为空是为了方便看,还有以后更改url。privatestaticfinal String VERSIONINFO_URL = "我现在是空的,这个要自己填自己的查询url";
    privatestaticfinalint HAVE_NEW_VERSION = 0;
    privatestaticfinalint ALREADY_NEW_VERSION = 1;
    private Context context = MyApplication.mContext;
    private UpdateInfo updateInfo;
    //获取到主线程的looper,对UI操作private Handler mHandler = new Handler(Looper.getMainLooper()) {
        @OverridepublicvoidhandleMessage(Message msg) {
            switch (msg.what) {
                case HAVE_NEW_VERSION:
                    openUpdateDialog();
                    break;
                case ALREADY_NEW_VERSION:
                    Toast.makeText(context, "已经是最新版本", Toast.LENGTH_LONG).show();
                    break;
            }
        }
    };
    privatevoidopenUpdateDialog() {
        AlertDialog.Builder builder = new AlertDialog.Builder(context);
        builder.setTitle("版本有更新");
        builder.setMessage(updateInfo.description);
        builder.setPositiveButton("确定", new DialogInterface.OnClickListener() {
            @OverridepublicvoidonClick(DialogInterface dialog, int which) {
                downloadNewVersion();
            }
        });
        builder.setNegativeButton("取消", null);
    }
    privatevoiddownloadNewVersion() {
        final ProgressDialog pd = new ProgressDialog(context);
        pd.setTitle("更新进度");
        pd.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
        pd.show();
        new Thread(new Runnable() {
            InputStream is;
            BufferedInputStream bis;
            FileOutputStream fos;
            @Overridepublicvoidrun() {
                //这里完成下载try {
                    URL downloadUrl = new URL(updateInfo.url);
                    HttpURLConnection connection = (HttpURLConnection) downloadUrl.openConnection();
                    connection.setConnectTimeout(8000);
                    connection.setReadTimeout(8000);
                    int maxlength = connection.getContentLength();
                    pd.setMax(maxlength);
                    is = connection.getInputStream();
                    bis = new BufferedInputStream(is);
                    File file = new File(Environment.getExternalStorageDirectory(), "newversion.apk");
                    fos = new FileOutputStream(file);
                    byte[] buffer = newbyte[1024];
                    int len;
                    int loaded = 0;
                    while ((len = bis.read(buffer)) != -1) {
                        fos.write(buffer, 0, len);
                        loaded += len;
                        pd.setProgress(loaded);
                    }
                    installApk(file);
                } catch (MalformedURLException e) {
                    e.printStackTrace();
                } catch (IOException e) {
                    e.printStackTrace();
                } finally {
                    try {
                        is.close();
                        bis.close();
                        fos.close();
                    } catch (IOException e) {
                        e.printStackTrace();
                    }
                }
            }
        }).start();
    }
    privatevoidinstallApk(File file) {
        Intent intent = new Intent();
        intent.setAction(Intent.ACTION_VIEW);
        intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
        context.startActivity(intent);
    }
    @Overridepublicvoidrun() {
        try {
            String s = VERSIONINFO_URL;
            URL url = new URL(s);
            HttpURLConnection connection = (HttpURLConnection) url.openConnection();
            connection.setConnectTimeout(8000);
            connection.setReadTimeout(8000);
            InputStream is = connection.getInputStream();
            InputStreamReader isr = new InputStreamReader(is);
            BufferedReader br = new BufferedReader(isr);
            Gson gson = new Gson();
            updateInfo = gson.fromJson(br, UpdateInfo.class);
            //后台版本int serverVersionCode = updateInfo.versionCode;
            //本地版本获取int localVersionCode = getLocalVersionCode();
            if (serverVersionCode > localVersionCode) {
                //后台版本新!所以弹框提醒用户有新版本,让用户操作dialog更新
                Message msg = new Message();
                msg.what = HAVE_NEW_VERSION;
                mHandler.sendMessage(msg);
            } else {
                //后台没有新版本,所以在界面反馈用户不用更新
                Message msg = new Message();
                msg.what = ALREADY_NEW_VERSION;
                mHandler.sendMessage(msg);
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (PackageManager.NameNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
    }
    privateintgetLocalVersionCode() throws PackageManager.NameNotFoundException {
        PackageManager pm = context.getPackageManager();
        PackageInfo info = pm.getPackageInfo(context.getPackageName(), 0);
        int versionCode = info.versionCode;
        return versionCode;
    }
}

好了,主要逻辑写完了那么就可以在btn中开线程做查询、下载、更新的事情了。

publicclassMainActivityextendsActivity {private Button btnDownload;
    private View.OnClickListener listener = new View.OnClickListener() {
        @OverridepublicvoidonClick(View v) {
            switch (v.getId()) {
                case R.id.btnDownload:
                //在这里做检查业务逻辑
                CheckVersion checkVersion = new CheckVersion();
                new Thread(checkVersion).start();
                break;
            }
        }
    };
    @OverrideprotectedvoidonCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        btnDownload = (Button) findViewById(R.id.btnDownload);
        btnDownload.setOnClickListener(listener);
    }
}

到这里,代码片全部写完。
最后用一张图回顾一下我都做了什么:

本文标签: 检查更新下载系统