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);
}
}
到这里,代码片全部写完。
最后用一张图回顾一下我都做了什么:
版权声明:本文标题:Android开发秘籍:构建自动更新功能,让你的应用永不过时 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:https://www.betaflare.com/biancheng/1773221470a3277015.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。


发表评论