android软件内在线更新已经算是android开发中必不可少的环节了,我也是因为项目需求,花了半天的时候调试好了前后端,期间参考了诸多博客,由于没有做记录,这里就不引用了。不多bb,直接上代码:
下面是工具类:
import java.io.File; import java.io.FileOutputStream; import java.io.IOException; import java.io.InputStream; import javax.net.ssl.HostnameVerifier; import javax.net.ssl.SSLContext; import javax.net.ssl.SSLSession; import javax.net.ssl.TrustManager; import javax.net.ssl.X509TrustManager; import okhttp3.Call; import okhttp3.Callback; import okhttp3.OkHttpClient; import okhttp3.Request; import okhttp3.Response; /** * 文件下载工具类(单例模式) */ public class DownloadUtil { private static DownloadUtil downloadUtil; private final OkHttpClient okHttpClient; public static DownloadUtil get() { if (downloadUtil == null) { downloadUtil = new DownloadUtil(); } return downloadUtil; } public DownloadUtil() { okHttpClient = getUnsafeOkHttpClient(); } private OkHttpClient getUnsafeOkHttpClient() { try { // Create a trust manager that does not validate certificate chains final TrustManager[] trustAllCerts = new TrustManager[] { new X509TrustManager() { @Override public void checkClientTrusted(java.security.cert.X509Certificate[] chain, String authType) { } @Override public void checkServerTrusted(java.security.cert.X509Certificate[] chain, String authType) { } @Override public java.security.cert.X509Certificate[] getAcceptedIssuers() { return new java.security.cert.X509Certificate[]{}; } } }; // Install the all-trusting trust manager final SSLContext sslContext = SSLContext.getInstance("SSL"); sslContext.init(null, trustAllCerts, new java.security.SecureRandom()); // Create an ssl socket factory with our all-trusting manager final javax.net.ssl.SSLSocketFactory sslSocketFactory = sslContext.getSocketFactory(); OkHttpClient.Builder builder = new OkHttpClient.Builder(); builder.sslSocketFactory(sslSocketFactory); builder.hostnameVerifier(new HostnameVerifier() { @Override public boolean verify(String hostname, SSLSession session) { return true; } }); OkHttpClient okHttpClient = builder.build(); return okHttpClient; } catch (Exception e) { throw new RuntimeException(e); } } /** * @param url 下载连接 * @param destFileDir 下载的文件储存目录 * @param destFileName 下载文件名称,后面记得拼接后缀,否则手机没法识别文件类型 * @param listener 下载监听 */ public void download(final String url, final String destFileDir, final String destFileName, final OnDownloadListener listener) { Request request = new Request.Builder() .url(url) .build(); //异步请求 okHttpClient.newCall(request).enqueue(new Callback() { @Override public void onFailure(Call call, IOException e) { // 下载失败监听回调 listener.onDownloadFailed(e); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; //储存下载文件的目录 File dir = new File(destFileDir); if (!dir.exists()) { dir.mkdirs(); } File file = new File(dir, destFileName); try { is = response.body().byteStream(); long total = response.body().contentLength(); fos = new FileOutputStream(file); long sum = 0; while ((len = is.read(buf)) != -1) { fos.write(buf, 0, len); sum += len; int progress = (int) (sum * 1.0f / total * 100); //下载中更新进度条 listener.onDownloading(progress); } fos.flush(); //下载完成 listener.onDownloadSuccess(file); } catch (Exception e) { listener.onDownloadFailed(e); }finally { try { if (is != null) { is.close(); } if (fos != null) { fos.close(); } } catch (IOException e) { } } } }); } public interface OnDownloadListener{ /** * 下载成功之后的文件 */ void onDownloadSuccess(File file); /** * 下载进度 */ void onDownloading(int progress); /** * 下载异常信息 */ void onDownloadFailed(Exception e); } }下面是应用:
private static ProgressDialog progressDialog = null; private final static int MAXVALUE = 100; private String apkFilePath=null; /** * 文件下载 */ private void downFile(String url) { DownloadUtil.get().download(url, apkFilePath, "kylvd.apk", new DownloadUtil.OnDownloadListener() { @Override public void onDownloadSuccess(File file) { Log.e("tag","down success"); sendMsg(2,0); sendMsg(3,0); } @Override public void onDownloading(int progress) { sendMsg(1,progress); } @Override public void onDownloadFailed(Exception e) { sendMsg(2,0); Log.e("tag","down Failed"); } }); } //安装apk,这里需要注意,8.0之后不可以把url直接暴露,需要先建立一个共享文件,再安装 private void installAPK() { Intent intent = new Intent(Intent.ACTION_VIEW); File apkFile = new File(apkFilePath+"/xxxx.apk"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri uri = FileProvider.getUriForFile(MainActivity.this, "com.example.administrator.provider", apkFile);//com.example.administrator.provider即是共享文件区 intent.setDataAndType(uri, "application/vnd.android.package-archive"); } else { intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); } startActivity(intent); }; //软件更新对话框 private void alertSofetUpdata(){ final TextView tv=new TextView(this); tv.setText("\n 检测到有新版本软件,点击确定更新\n\n"); tv.setTextSize(alert_text_size); AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setTitle("警告") .setIcon(R.mipmap.warning) .setView(tv) .setPositiveButton(" 确定", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialogInterface, int i) { if (progressDialog ==null){ progressDialog = new ProgressDialog(MainActivity.this); progressDialog.setMax(MAXVALUE); progressDialog.setTitle("软件下载中"); progressDialog.setMessage("软件下载中,请稍后..."); //这里设置为不可以通过按取消按钮关闭进度条 progressDialog.setCancelable(false); progressDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); //这里设置的是是否显示进度,设为false才是显示的哦! progressDialog.setIndeterminate(false); progressDialog.show(); } downFile("http://xxxx"); } }) .setNegativeButton("取消 ",null); AlertDialog dialog = builder.create(); dialog.show(); dialog.getButton(AlertDialog.BUTTON_POSITIVE).setTextSize(24); dialog.getButton(AlertDialog.BUTTON_NEGATIVE).setTextSize(24); } /** * 发送Handler */ public void sendMsg(int what, Object object) { Message msg = new Message(); msg.what = what; msg.obj = object; mHandler.sendMessage(msg); } /** * Handler */ private Handler mHandler = new Handler(Looper.myLooper()) { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 1: progressDialog.setProgress((int)msg.obj); break; case 2: progressDialog.dismiss(); progressDialog=null; break; case 3: installAPK(); break; } } };在Manifest中添加共享文件,注意,android:authorities=“com.example.administrator.provider"需要修改为自己的包名,android:resource=”@xml/filepaths"为文件路径
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.administrator.provider" android:exported="false" android:grantUriPermissions="true" tools:ignore="WrongManifestParent"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/filepaths" /> </provider>下面建立在res下建立xml/filepaths文件,path修改为自己的包名
<paths xmlns:android="http://schemas.android.com/apk/res/android"> <external-path name="files_root" path="Android/data/com.example.administrator.demo/"/> </paths>以上是android端的代码,后端实现起来比较简单了,建立一个文件下载服务器,建立一个http服务器,android请求服务,对比服务器版本和当前版本,不一致则下载更新。