|
|
@@ -0,0 +1,390 @@
|
|
|
+package com.qy.agv.update;
|
|
|
+
|
|
|
+import android.annotation.SuppressLint;
|
|
|
+import android.app.AlertDialog.Builder;
|
|
|
+import android.app.Dialog;
|
|
|
+import android.app.Notification;
|
|
|
+import android.app.NotificationManager;
|
|
|
+import android.app.PendingIntent;
|
|
|
+import android.content.Context;
|
|
|
+import android.content.Intent;
|
|
|
+import android.content.pm.PackageManager;
|
|
|
+import android.content.pm.ResolveInfo;
|
|
|
+import android.content.res.Resources.NotFoundException;
|
|
|
+import android.net.Uri;
|
|
|
+import android.os.Build;
|
|
|
+import android.os.Environment;
|
|
|
+import android.os.Handler;
|
|
|
+import android.os.Looper;
|
|
|
+import android.os.Message;
|
|
|
+import android.os.StrictMode;
|
|
|
+import android.util.Log;
|
|
|
+import android.view.LayoutInflater;
|
|
|
+import android.view.View;
|
|
|
+import android.widget.ProgressBar;
|
|
|
+import android.widget.TextView;
|
|
|
+
|
|
|
+import androidx.annotation.RequiresApi;
|
|
|
+import androidx.core.content.FileProvider;
|
|
|
+
|
|
|
+import com.qy.agv.R;
|
|
|
+import com.qy.agv.util.ProjectUtils;
|
|
|
+import com.qy.agv.util.StringUtils;
|
|
|
+import com.qy.agv.util.ToastUtils;
|
|
|
+import com.qy.agv.util.VersionUtils;
|
|
|
+
|
|
|
+import org.apache.log4j.Logger;
|
|
|
+
|
|
|
+import java.io.File;
|
|
|
+import java.io.FileOutputStream;
|
|
|
+import java.io.InputStream;
|
|
|
+import java.net.HttpURLConnection;
|
|
|
+import java.net.MulticastSocket;
|
|
|
+import java.net.SocketTimeoutException;
|
|
|
+import java.net.URL;
|
|
|
+import java.text.DecimalFormat;
|
|
|
+import java.util.HashMap;
|
|
|
+import java.util.List;
|
|
|
+
|
|
|
+public class UpdateManager {
|
|
|
+
|
|
|
+ private static final String TAG = "UpdateManager";
|
|
|
+ private static String FILE_NAME = "byjr_slam.apk";
|
|
|
+ /* 下载中 */
|
|
|
+ private static final int DOWNLOAD = 1;
|
|
|
+ /* 下载结束 */
|
|
|
+ private static final int DOWNLOAD_FINISH = 2;
|
|
|
+ /* 下载结束 */
|
|
|
+ private static final int ERROR = 3;
|
|
|
+ /* 保存解析的XML信息 */
|
|
|
+ HashMap<String, String> mHashMap;
|
|
|
+ /* 下载保存路径 */
|
|
|
+ private String mSavePath;
|
|
|
+ /* 记录进度条数量 */
|
|
|
+ private int progress;
|
|
|
+ /* 是否取消更新 */
|
|
|
+ private boolean cancelUpdate = false;
|
|
|
+
|
|
|
+ private Context mContext;
|
|
|
+
|
|
|
+ // 下载文件大小
|
|
|
+ private String fileSize;
|
|
|
+ // 已下载文件大小
|
|
|
+ private String tmpFileSize;
|
|
|
+
|
|
|
+ /* 更新进度条 */
|
|
|
+ private ProgressBar mProgress;
|
|
|
+ private TextView mProgressText;
|
|
|
+ private Dialog mDownloadDialog;
|
|
|
+ private Dialog mShowDialog;
|
|
|
+ public static Logger mylog =Logger.getLogger(UpdateManager.class);
|
|
|
+ public String next_version;
|
|
|
+
|
|
|
+ /* 通知栏 */
|
|
|
+ private NotificationManager updateNotificationManager = null;
|
|
|
+ private Notification updateNotification = null;
|
|
|
+
|
|
|
+ /* 通知栏跳转Intent */
|
|
|
+ private Intent updateIntent = null;
|
|
|
+ private PendingIntent updatePendingIntent = null;
|
|
|
+
|
|
|
+ private final Handler mHandler = new Handler(Looper.myLooper()) {
|
|
|
+ @SuppressLint("HandlerLeak")
|
|
|
+ @RequiresApi(api = Build.VERSION_CODES.O)
|
|
|
+ public void handleMessage(Message msg) {
|
|
|
+ switch (msg.what) {
|
|
|
+ // 正在下载
|
|
|
+ case DOWNLOAD:
|
|
|
+ // 设置进度条位置
|
|
|
+ if(mProgress!=null){
|
|
|
+ mProgress.setProgress(progress);
|
|
|
+ mProgressText.setText(tmpFileSize + "/" + fileSize);
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ case DOWNLOAD_FINISH:
|
|
|
+ // 安装文件
|
|
|
+// install();
|
|
|
+ ToastUtils.showToastL(mContext, "下载完成,开始安装");
|
|
|
+ installApk();
|
|
|
+ break;
|
|
|
+ case ERROR:
|
|
|
+ // 构造对话框
|
|
|
+ ToastUtils.showToast(mContext,"文件下载失败: "+ msg.obj.toString());
|
|
|
+// try {
|
|
|
+// checkUpdate();
|
|
|
+// }catch (Exception ex){
|
|
|
+// ex.printStackTrace();
|
|
|
+// }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ public UpdateManager(Context context) {
|
|
|
+ this.mContext = context;
|
|
|
+ }
|
|
|
+
|
|
|
+ public UpdateManager(Context context, HashMap<String,String> mHashMap) {
|
|
|
+ this.mContext = context;
|
|
|
+ this.mHashMap = mHashMap;
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检测软件更新
|
|
|
+ *
|
|
|
+ * @throws Exception
|
|
|
+ * @throws NotFoundException
|
|
|
+ */
|
|
|
+// @RequiresApi(api = Build.VERSION_CODES.O)
|
|
|
+ public void checkUpdate() throws Exception {
|
|
|
+ if (isUpdate()) {
|
|
|
+ if(!StringUtils.isEmpty(next_version)){
|
|
|
+ ToastUtils.showToastL(mContext, "更新到版本"+next_version);
|
|
|
+ }else{
|
|
|
+ ToastUtils.showToastL(mContext, "正在更新");
|
|
|
+ }
|
|
|
+ ProjectUtils.init();
|
|
|
+ showDownloadDialog();
|
|
|
+// downloadApk();
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 检查软件是否有更新版本
|
|
|
+ *
|
|
|
+ * @return
|
|
|
+ * @throws Exception
|
|
|
+ */
|
|
|
+ @SuppressLint("NewApi")
|
|
|
+ public boolean isUpdate() throws Exception {
|
|
|
+ // 获取当前软件版本
|
|
|
+ try {
|
|
|
+ int versionCode = VersionUtils.getVersionCode(mContext);
|
|
|
+ UpdateXmlService service = new UpdateXmlService();
|
|
|
+ String path = ProjectUtils.getProjectURL() + "/version.xml";
|
|
|
+ URL url = new URL(path);
|
|
|
+ HttpURLConnection conn = (HttpURLConnection) url.openConnection();
|
|
|
+ conn.setReadTimeout(5 * 1000);
|
|
|
+ conn.setConnectTimeout(3000);
|
|
|
+ conn.setRequestMethod("GET");
|
|
|
+ StrictMode.ThreadPolicy policy = new StrictMode.ThreadPolicy.Builder()
|
|
|
+ .permitAll().build();
|
|
|
+ StrictMode.setThreadPolicy(policy);
|
|
|
+ InputStream inStream = conn.getInputStream();
|
|
|
+ mHashMap = service.parseXml(inStream);
|
|
|
+ if (null != mHashMap) {
|
|
|
+ int serviceCode = Integer.valueOf(mHashMap.get("version"));
|
|
|
+ // 版本判断
|
|
|
+ if (serviceCode > versionCode) {
|
|
|
+ next_version = mHashMap.get("version_name");
|
|
|
+ return true;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ } catch (SocketTimeoutException ex){
|
|
|
+ ToastUtils.showToast(mContext, "连接超过");
|
|
|
+ } catch (Exception e) {
|
|
|
+ Log.e(TAG, "meth:isUpdate");
|
|
|
+ throw e;
|
|
|
+ }
|
|
|
+ return false;
|
|
|
+ }
|
|
|
+
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 显示软件下载对话框
|
|
|
+ */
|
|
|
+ public void showDownloadDialog() {
|
|
|
+ // 构造软件下载对话框
|
|
|
+ Builder builder = new Builder(mContext);
|
|
|
+ builder.setTitle(R.string.soft_updating);
|
|
|
+ // 给下载对话框增加进度条
|
|
|
+ final LayoutInflater inflater = LayoutInflater.from(mContext);
|
|
|
+ View v = inflater.inflate(R.layout.softupdate_progress, null);
|
|
|
+ mProgress = (ProgressBar) v.findViewById(R.id.update_progress);
|
|
|
+ mProgressText = (TextView) v.findViewById(R.id.update_progress_text);
|
|
|
+ builder.setView(v);
|
|
|
+ // 取消更新
|
|
|
+// builder.setNegativeButton(R.string.soft_update_close,(dialog,which)-> dialog.dismiss());
|
|
|
+ mDownloadDialog = builder.create();
|
|
|
+ mDownloadDialog.setCancelable(false);
|
|
|
+ mDownloadDialog.setCanceledOnTouchOutside(false);
|
|
|
+ mDownloadDialog.show();
|
|
|
+ downloadApk();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载apk文件
|
|
|
+ */
|
|
|
+ private void downloadApk() {
|
|
|
+ // 启动新线程下载软件
|
|
|
+ new downloadApkThread().start();
|
|
|
+ }
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 下载文件线程
|
|
|
+ */
|
|
|
+ private class downloadApkThread extends Thread {
|
|
|
+ @Override
|
|
|
+ public void run() {
|
|
|
+ try {
|
|
|
+ // 判断SD卡是否存在,并且是否具有读写权限
|
|
|
+ if (Environment.getExternalStorageState().equals(
|
|
|
+ Environment.MEDIA_MOUNTED)) {
|
|
|
+ // 获得存储卡的路径
|
|
|
+// File path = Environment.getExternalStorageDirectory();
|
|
|
+ // mSavePath = mContext.getExternalCacheDir().getAbsolutePath();
|
|
|
+
|
|
|
+ URL url = new URL(ProjectUtils.getProjectURL()
|
|
|
+ + mHashMap.get("url") + "/" + mHashMap.get("name"));
|
|
|
+ FILE_NAME = mHashMap.get("name");
|
|
|
+ mSavePath= ProjectUtils.APK;
|
|
|
+// URL url = new URL(ip + "/shares/android/"
|
|
|
+// + mHashMap.get("url")+"/"+mHashMap.get("name"));
|
|
|
+ // 创建连接
|
|
|
+ HttpURLConnection conn = (HttpURLConnection) url
|
|
|
+ .openConnection();
|
|
|
+ conn.setRequestProperty("Accept-Encoding", "identity");
|
|
|
+ conn.connect();
|
|
|
+ // 获取文件大小
|
|
|
+ int length = conn.getContentLength();
|
|
|
+ // 显示文件大小格式:2个小数点显示
|
|
|
+ DecimalFormat df = new DecimalFormat("0.00");
|
|
|
+ fileSize = df.format((float) length / 1024 / 1024)
|
|
|
+ + "MB";
|
|
|
+ // 创建输入流
|
|
|
+ InputStream is = conn.getInputStream();
|
|
|
+
|
|
|
+ File file = new File(mSavePath);
|
|
|
+ // 判断文件目录是否存在
|
|
|
+ if (!file.exists()) {
|
|
|
+ file.mkdir();
|
|
|
+ }else {
|
|
|
+ try {
|
|
|
+ for (File f : file.listFiles()) {
|
|
|
+ f.delete();
|
|
|
+ }
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }
|
|
|
+ File apkFile = new File(mSavePath, FILE_NAME);
|
|
|
+ FileOutputStream fos = new FileOutputStream(apkFile);
|
|
|
+ int count = 0;
|
|
|
+ // 缓存
|
|
|
+ byte buf[] = new byte[1024];
|
|
|
+ // 写入到文件中
|
|
|
+ do {
|
|
|
+ int numread = is.read(buf);
|
|
|
+ count += numread;
|
|
|
+ // 计算进度条位置
|
|
|
+ tmpFileSize = df.format((float) count / 1024 / 1024)
|
|
|
+ + "MB";
|
|
|
+ progress = (int) (((float) count / length) * 100);
|
|
|
+ // 更新进度
|
|
|
+ mHandler.sendEmptyMessage(DOWNLOAD);
|
|
|
+ if (numread <= 0) {
|
|
|
+ // 下载完成
|
|
|
+ mHandler.sendEmptyMessage(DOWNLOAD_FINISH);
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ // 写入文件
|
|
|
+ fos.write(buf, 0, numread);
|
|
|
+ } while (!cancelUpdate);// 点击取消就停止下载.
|
|
|
+ fos.close();
|
|
|
+ is.close();
|
|
|
+ }
|
|
|
+
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ mylog.error("文件下载失败:", e);
|
|
|
+ Message msg = new Message();
|
|
|
+ msg.what = ERROR;
|
|
|
+ msg.obj = e.getMessage();
|
|
|
+ mHandler.sendMessage(msg);
|
|
|
+ }
|
|
|
+ // 取消下载对话框显示
|
|
|
+// mDownloadDialog.dismiss();
|
|
|
+ }
|
|
|
+ };
|
|
|
+
|
|
|
+ /**
|
|
|
+ * 安装APK文件
|
|
|
+ */
|
|
|
+ private void installApk() {
|
|
|
+ File apkfile = null;
|
|
|
+ for (int i = 0;i<5;i++) {
|
|
|
+ apkfile = new File(mSavePath, FILE_NAME);
|
|
|
+ if (!apkfile.exists()) {
|
|
|
+ try {
|
|
|
+ Thread.sleep(1000);
|
|
|
+ }catch (Exception e){
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ }else{
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!apkfile.exists()) {
|
|
|
+ ToastUtils.showToast(mContext,"文件不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+// openAssignFolder(mSavePath);
|
|
|
+ // 通过Intent安装APK文件
|
|
|
+ Intent install = new Intent(Intent.ACTION_VIEW);
|
|
|
+ install.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
|
|
|
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
|
|
|
+ install.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
|
|
|
+ Uri apkUri = FileProvider.getUriForFile(mContext, "com.byjr.app.fileprovider", apkfile);//在AndroidManifest中的android:authorities值
|
|
|
+ install.setDataAndType(apkUri, "application/vnd.android.package-archive");
|
|
|
+ // 查询所有符合 intent 跳转目标应用类型的应用,注意此方法必须放置在 setDataAndType 方法之后
|
|
|
+ List<ResolveInfo> resolveLists = mContext.getPackageManager().queryIntentActivities(install, PackageManager.MATCH_DEFAULT_ONLY);
|
|
|
+ // 然后全部授权
|
|
|
+ for (ResolveInfo resolveInfo : resolveLists){
|
|
|
+ String packageName = resolveInfo.activityInfo.packageName;
|
|
|
+ mContext.grantUriPermission(packageName, apkUri, Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ install.setDataAndType(Uri.fromFile(apkfile), "application/vnd.android.package-archive");
|
|
|
+ }
|
|
|
+ mContext.startActivity(install);
|
|
|
+ }
|
|
|
+
|
|
|
+ /* 卸载apk */
|
|
|
+ public static void uninstallApk(Context context, String packageName) {
|
|
|
+ Uri uri = Uri.parse("package:" + packageName);
|
|
|
+ Intent intent = new Intent(Intent.ACTION_DELETE, uri);
|
|
|
+ context.startActivity(intent);
|
|
|
+ }
|
|
|
+
|
|
|
+ public void install(){
|
|
|
+ File apkfile = null;
|
|
|
+ try {
|
|
|
+ for (int i = 0; i < 5; i++) {
|
|
|
+ apkfile = new File(mSavePath, FILE_NAME);
|
|
|
+ if (!apkfile.exists()) {
|
|
|
+ try {
|
|
|
+ Thread.sleep(1000);
|
|
|
+ } catch (Exception e) {
|
|
|
+ e.printStackTrace();
|
|
|
+ }
|
|
|
+ } else {
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ }
|
|
|
+ if (!apkfile.exists()) {
|
|
|
+ ToastUtils.showToast(mContext, "文件不存在");
|
|
|
+ return;
|
|
|
+ }
|
|
|
+ Intent install = new Intent(Intent.ACTION_VIEW);
|
|
|
+ install.setDataAndType(Uri.parse(apkfile.getAbsolutePath()), "application/vnd.android.package-archive");
|
|
|
+ install.putExtra("IMPLUS_INSTALL", "SILENT_INSTALL");
|
|
|
+ mContext.startActivity(install);
|
|
|
+ }catch (Exception ex){
|
|
|
+ ex.printStackTrace();
|
|
|
+ ToastUtils.showToast(mContext, "更新失败");
|
|
|
+ }
|
|
|
+ }
|
|
|
+}
|