1.第三方app库:
https://github.com/WVector/AppUpdate、
引用:
api 'com.qianwen:update-app:3.5.2'
2.可在主页中请求接口判断是否要更新:
ApkUpdateUtils.appUpdate(mActivity);
3.ApkUpdateUtils
public class ApkUpdateUtils { public static AppVersionBean appVersionBean; public static File apkFile = null; public static void appUpdate(final Activity activity) { String path = MyApplication.getInstance().getExternalCacheDir().getAbsolutePath(); String mUpdateUrl = "http"; new UpdateAppManager .Builder() //必须设置,当前Activity .setActivity(activity) .setTargetPath(path) //必须设置,实现httpManager接口的对象 .setHttpManager(new UpdateHttpUtil()) //必须设置,更新地址 .setUpdateUrl(mUpdateUrl) .setPost(false) .build().checkNewApp(new UpdateCallback() { /** * 解析json,自定义协议 * * @param json 服务器返回的json * @return UpdateAppBean */ @Override protected UpdateAppBean parseJson(String json) { appVersionBean = new Gson().fromJson(json, AppVersionBean.class); UpdateAppBean updateAppBean = new UpdateAppBean(); try { JSONObject jsonObject = new JSONObject(json); updateAppBean //(必须)是否更新Yes,No .setUpdate("Yes") //(必须)新版本号, .setNewVersion(appVersionBean.getVersion()) //(必须)下载地址 .setApkFileUrl(appVersionBean.getLink()) //(必须)更新内容 .setUpdateLog(appVersionBean.getDescription()) //大小,不设置不显示大小,可以不设置 //.setTargetSize(jsonObject.optString("target_size")) //是否强制更新,可以不设置 .setConstraint(true); //设置md5,可以不设置 // .setNewMd5(jsonObject.optString("new_md5")); } catch (JSONException e) { e.printStackTrace(); } return updateAppBean; } /** * 有新版本 * * @param updateApp 新版本信息 * @param updateAppManager app更新管理器 */ @Override public void hasNewApp(UpdateAppBean updateApp, final UpdateAppManager updateAppManager) { //自定义对话框 final VersionDialog dialog = new VersionDialog(activity, appVersionBean); dialog.setListerner(new VersionDialog.VersionListerner() { @Override public void startDownload() { updateAppManager.download(new DownloadService.DownloadCallback() { @Override public void onStart() { dialog.showProgressUi(); } /** * 进度 * * @param progress 进度 0.00 -1.00 ,总大小 * @param totalSize 总大小 单位B */ @Override public void onProgress(final float progress, long totalSize) { activity.runOnUiThread(new Runnable() { @Override public void run() { dialog.updateProgress((int) progress); } }); } /** * * @param total 总大小 单位B */ @Override public void setMax(long total) { } @Override public boolean onFinish(File file) { apkFile = file; return true; } @Override public void onError(String msg) { activity.runOnUiThread(new Runnable() { @Override public void run() { dialog.hideProgressUi(); } }); } @Override public boolean onInstallAppAndAppOnForeground(File file) { return false; } }); } @Override public void install() { AppUpdateUtils.installApp(activity, apkFile); } }); dialog.show(); } /** * 网络请求之前 */ @Override public void onBefore() { } /** * 网路请求之后 */ @Override public void onAfter() { } /** * 没有新版本 */ @Override public void noNewApp(String error) { } }); } }
4.UpdateHttpUtil (自定义网络下载)
public class UpdateHttpUtil implements HttpManager { @Override public void asyncGet(@NonNull String url, @NonNull Map, String> params, @NonNull final Callback callBack) { final int versionCode = DeviceUtils.getVersionCode(MyApplication.getInstance()); RetrofitCreateHelper.createApi(CommonLibraryApi.class) .getAppVersions(versionCode, "android").compose(RxHelper. >rxSchedulerHelper()) .subscribe(new Consumer
>() { @Override public void accept(List
appVersionBean) throws Exception { //可以在判断版本之后在设置是否强制更新或者VersionParams if (appVersionBean != null && !appVersionBean.isEmpty() && versionCode < appVersionBean.get(0).getVersion_code()) { callBack.onResponse(new Gson().toJson(appVersionBean.get(0))); } } }, new Consumer () { @Override public void accept(Throwable throwable) throws Exception { Log.d("version", "accept: " + throwable.getMessage()); } }); } @Override public void asyncPost(@NonNull String url, @NonNull Map , String> params, @NonNull Callback callBack) { } @Override public void download(@NonNull String url, @NonNull final String path, @NonNull final String fileName, @NonNull final FileCallback callback) { OkHttpClient.Builder okHttpClient = new OkHttpClient.Builder(); OkHttpClient client = okHttpClient .retryOnConnectionFailure(true) .sslSocketFactory(DownloadFileUrlConnectionImpl.createSSLSocketFactory()) .connectTimeout(60, TimeUnit.SECONDS) .readTimeout(60, TimeUnit.SECONDS) .writeTimeout(60, TimeUnit.SECONDS).build(); Request request = new Request.Builder().url(url).build(); client.newCall(request).enqueue(new okhttp3.Callback() { @Override public void onFailure(Call call, IOException e) { Log.e("pdf", "onFailure: " + e.getMessage()); } @Override public void onResponse(Call call, Response response) throws IOException { InputStream is = null; byte[] buf = new byte[2048]; int len = 0; FileOutputStream fos = null; try { is = response.body().byteStream(); long total = response.body().contentLength(); File dir = new File(path); IoUtils.createFolder(dir); File file = new File(dir, fileName); IoUtils.delFileOrFolder(file); 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); // 下载中 Log.e("apk", "onLoad: " + progress); callback.onProgress(progress, total); } fos.flush(); // 下载完成 callback.onResponse(file); } catch (Exception e) { callback.onError("异常"); } finally { try { if (is != null) is.close(); } catch (IOException e) { } try { if (fos != null) fos.close(); } catch (IOException e) { } } } }); } }
5.自定义VersionDialog (含有非强制更新,强制更新一些列操作,后台返回的是markdown格式,结合需求自己定义)
public class VersionDialog extends Dialog { AppVersionBean appVersionBean; private LinearLayout ll_progress; private TextView tv_progress; private ProgressBar pb; private TextView tvInstall; private boolean isForceUpdate; //true 强制更新, public VersionDialog(@NonNull Context context, AppVersionBean appVersionBean) { super(context); this.appVersionBean = appVersionBean; isForceUpdate = appVersionBean.getIs_forced() > 0; } @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); Window window = getWindow(); window.setGravity(Gravity.CENTER); window.setBackgroundDrawable(new ColorDrawable(Color.TRANSPARENT)); requestWindowFeature(Window.FEATURE_NO_TITLE); setContentView(R.layout.custom_dialog_two_layout); TextView tvTitle = (TextView) findViewById(com.ls.commonlibrary.R.id.tv_title); final MarkdownView mdMsg = (MarkdownView) findViewById(com.ls.commonlibrary.R.id.md_msg); TextView tvAbord = (TextView) findViewById(com.ls.commonlibrary.R.id.tv_abord); tvInstall = (TextView) findViewById(com.ls.commonlibrary.R.id.versionchecklib_version_dialog_commit); View line = findViewById(com.ls.commonlibrary.R.id.view_line); ImageView close = (ImageView) findViewById(com.ls.commonlibrary.R.id.img_close); ll_progress = (LinearLayout) findViewById(R.id.ll_progress); tv_progress = (TextView) findViewById(R.id.tv_progress); pb = (ProgressBar) findViewById(R.id.pb); //可以使用之前从service传过来的一些参数比如:title。msg,downloadurl,parambundle tvTitle.setText("V" + appVersionBean.getVersion() + "版本更新"); InternalStyleSheet css = new Github(); css.addRule(".container", "padding-right:0", ";padding-left:0", "text-align:justify", "text-align-last:left", "letter-spacing: 0.3px"); css.addRule("body", "line-height: 1.59", "padding: 0px", "font-size: 17px", "color: " + "#333333"); css.addRule("h1", "color: #333333", "size: 25px", "margin-top: 30px", "magin-bottom: " + "30px", "text-align: left"); css.addRule("h2", "color: #333333", "size: 23px", "margin-top: 30px", "magin-bottom: " + "30px", "text-align: left"); css.addRule("h3", "color: #333333", "size: 21px", "margin-top: 30px", "magin-bottom: " + "30px", "text-align: left"); css.addRule("h4", "color: #333333", "size: 19px", "margin-top: 30px", "magin-bottom: " + "30px", "text-align: left"); css.addRule("img", "margin-top: 20px", "margin-bottom: 20px", "align:center", "margin: 0 " + "auto", "max-width: 100%", "display: block"); /*设置 a 标签文字颜色,不知道为什么,要这样混合才能有效*/ css.addMedia("color: #59b6d7; a:link {color: #59b6d7}"); css.endMedia(); css.addRule("a", "font-weight: bold"); mdMsg.addStyleSheet(css); mdMsg.loadMarkdown(appVersionBean.getDescription()); WebViewClient mWebViewClient = new WebViewClient() { /** * 多页面在同一个 WebView 中打开,就是不新建 activity 或者调用系统浏览器打开 */ @Override public boolean shouldOverrideUrlLoading(WebView view, String url) { view.loadUrl(url); return true; } /** * 网页开始加载 * @param view * @param url * @param favicon */ @Override public void onPageStarted(WebView view, String url, Bitmap favicon) { super.onPageStarted(view, url, favicon); } /** * 网页加载结束 */ @Override public void onPageFinished(WebView view, String url) { super.onPageFinished(view, url); mdMsg.scrollTo(0, 0); } @Override public void onReceivedError(WebView view, int errorCode, String description, String failingUrl) { System.out.println("errorCode = " + errorCode); super.onReceivedError(view, errorCode, description, failingUrl); } }; mdMsg.setWebViewClient(mWebViewClient); tvInstall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { tvInstall.setVisibility(View.GONE); ll_progress.setVisibility(View.VISIBLE); if (listerner != null) { listerner.startDownload(); } } }); if (!isForceUpdate) { line.setVisibility(View.VISIBLE); close.setVisibility(View.VISIBLE); close.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View view) { dismiss(); } }); } setCanceledOnTouchOutside(!isForceUpdate); setCancelable(!isForceUpdate); if (isForceUpdate) { setOnKeyListener(new DialogInterface.OnKeyListener() { @Override public boolean onKey(DialogInterface dialog, int keyCode, KeyEvent event) { if (keyCode == KeyEvent.KEYCODE_BACK) { return true; } else { return false; //默认返回 false } } }); } } public void updateProgress(int progress) { tv_progress.setText(progress + "%"); pb.setProgress(progress); if (progress == 100) { hideProgressUi(); tvInstall.setText("安装"); tvInstall.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { if (listerner != null) { listerner.install(); } } }); } } VersionListerner listerner; public void setListerner(VersionListerner listerner) { this.listerner = listerner; } public interface VersionListerner { void startDownload(); void install(); } public void showProgressUi() { tvInstall.setVisibility(View.GONE); ll_progress.setVisibility(View.VISIBLE); } public void hideProgressUi() { tvInstall.setText("重新下载"); tvInstall.setVisibility(View.VISIBLE); ll_progress.setVisibility(View.GONE); } }