背景:因为手头上做的这个app在Android上没有进行大规模的团队开发,但是想先发给玩家进行测试。所以就需要在app中添加一个更新的模块。
效果:进入app的时候,就会检测当前的版本是不是最新的版本,如果是的话就会进行弹窗提示,设置弹窗是否可以关闭来代表此次更新是否是强制的更新。
使用的框架是okhttp3
github的地址是:https://github.com/square/okhttp
1、首先我们需要一个http服务器。因为我们需要将我们的新版本的安装包和一个说明文件放在这个服务器上,然后客户端通过网络去获取这两个东西。
因为我们一旦检测到有版本的更新的话,我们的弹窗里面就需要去显示此次更新的内容有哪些,所以这个弹窗里面的内容我们不能写死,只能从服务器去获取
2、我们需要一个新的apk,和一个Json文件,新的apk作为Demo中更新的新版本apk,我们只需要让他界面不同就可以,还有一个Json文件,这个Json文件里面我们需要存放一些信息,比如此次更新了哪些内容,然后我们应该去哪里才能得到新的apk,还新的apk文件的md5码,我们需要这个码来做校验。因为项目的需要,我在里面还存放了此次版本升级的等级,如果等级是:HIGH的话,弹窗就不能关闭,也就是强制性升级,如果是LOW的话,弹窗就可以关闭,也就是看玩家自己需求去更新。
3、我们的代码结构比较简单:
A.网络部分:用来进行get,download等操作
B.ui,弹窗
C.Json解析:因为我们熊服务器首先获取的内容是一个json文本,用来填充弹窗的内容等,所以需要先解析一下
D.其他:因为我们里面需要进行apk文件的拷贝以及新生成安装界面去安装apk,所以这些杂七杂八的事情统一归置到一个工具类
然后我们声明一个AppUpdater.java,里面归纳了上面写部分的所有接口,这我们在MainActivity里面只需要声明一个AppUpddater的对象,这样就可以干所有的事情了。
下面我们来进行每一个部分的解析:
A部分:网络部分,用来进行get,download等操作
用来进行get,download等操作
get操作其实也就是download操作,只不过download的是一个json文本,这文本里面存放的信息有这些:
{
"title":"当前版本:1.4.5!",
"content":"1. 优化了bug1;\n2. 上线了功能2 ;\n3. 修复了一些问题。",
"url":"http://192.168.0.104:8083/MyApplication.apk",
"md5":"bd90eda125f34bf2aed1876417cb3523",
"versionCode":"450"
}
里面的信息前面两个是我们在弹窗里面显示内容,我们get到的信息,之后可以建一个类,然后将这些变量储存在对象中的每一个成员当中,url是我们服务器的地址,访问这个地址我们可以获取到这个apk(这里使用的是我自己搭建的http服务器,可能当你们看到这个文章的时候,我的服务器已经关掉了,所以不需要大惊小怪~~~)
KNetGetCallback类:
我们在使用get操作去get这个json文件之后,如果成功服务器会给我们返回一段字符,如果失败,就会返回错误的信息,然后我们就需要调对应的回调函数
public interface KNetGetCallback {
// get成功的话应该返回一个json字符串
void getSuccess(String reponse);
//get失败抛出异常
void getFailed(Throwable throeable);
}
初次之外,我们还需要一个DownLoad类,去Download我们的apk,这个类和上面的其实本质上是一样的,都是从服务器去获取文件,只不过物品,我们把上面的那个叫做Get操作,然后我们把这里的叫做DownLoad操作,然后当我们DownLoad完成之后,成功:我们应该怎么做,失败,我们应该怎么做。这里我们还多余了一个成员函数,就是获取当前下载的文件的进度,用来给用户显示。
Tip:之所以第一步的Get操作不用显示下载进度,是因为我们第一步获取的只是一个简单的文本文件,很小,所以没必要去显示,获取的进度,对于用户,这里我们只需要Get Json文件的内容就可以。
package com.appupdata.updata.net;
import java.io.File;
public interface KNetDownLoadCallback {
// 下载成功应该返回一个文件,这个时候应该是一个apk文件
void downloadSuccess(File apkFile);
// 下载失败抛出异常
void downloadfailed(Throwable throowable);
// 下载的过程返回进度
void downloadProgress(int progress);
}
上面就是我们分别对应获取Json文本以及apk文件的回调,下面就是我们对应的请求操作了:
package com.appupdata.updata.net;
import java.io.File;
public interface KNetManager {
//需要让服务器返回一段json数据,告诉我们要不要进行应用升级
void get(String url,KNetGetCallback callback,Object tag);
// 下载
void download(String url, File targetFile,KNetDownLoadCallback callback,Object tag);
// 取消
void cancel(Object tag);
}
第一个get函数就是我们对应去get Json文本的函数,第一个参数是url,第二个参数是获取成功或者获取失败的回调,第三个是一个标志位, 我们可以使用这个标志位去进行对应的取消操作,就在第三个函数。
第二个函数是我们DownLoad APK文件的函数,第一个参数就是url,第二个是我们传进来的一个空的文件,因为这个时候,我们需要将apk文件从服务器上面读下来,储存在本地。所以我们需要一个空文件来写,第三个参数使我们之前设置的DownLoad回调,第四个参数是我们操作的标志位。
第三个成员函数:cancel是我们为用户的取消操作,而设置的,因为有时候,当用户在下载到一半的时候,可能因为突发情况,而停止下载,这个时候,如果不设置没有对应的处理措施,就可能有异常状况发生。
以上就是我们准备的接口类,KNetManager里面使用的是KNetGetCallback,KNetDownLoadCallback接口。后面的两个接口,等我们具体使用的时候再去实现里面的成员函数。
对于KNetManager我们创建一个OkHttpNetManager的类去实现里面的三个成员函数:
我会这代码里面进行详细的注释,解释怎么创建一个请求,以及当你的服务器是https的时候我们应该怎么设置证书之类的。
Talk is cheap,show me the code(装个13)
package com.appupdata.updata.net;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.appupdata.MainActivity;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.security.KeyManagementException;
import java.security.KeyStore;
import java.security.KeyStoreException;
import java.security.NoSuchAlgorithmException;
import java.security.SecureRandom;
import java.security.cert.Certificate;
import java.security.cert.CertificateException;
import java.security.cert.CertificateFactory;
import java.security.cert.X509Certificate;
import java.util.Arrays;
import java.util.List;
import java.util.concurrent.TimeUnit;
//import java.util.logging.Handler;
import javax.net.ssl.HostnameVerifier;
import javax.net.ssl.HttpsURLConnection;
import javax.net.ssl.SSLContext;
import javax.net.ssl.SSLSession;
import javax.net.ssl.SSLSocketFactory;
import javax.net.ssl.TrustManager;
import javax.net.ssl.TrustManagerFactory;
import javax.net.ssl.X509TrustManager;
impo