今天产品又有特大喜讯啦,App要添加新功能了普(ma)天(de)同(zhi)庆(zhang)~~~
登陆页面就强制用户更新。。。
脑壳疼+1
写吧
首先是三个工具类
apk
public class InstallApk { Activity context; public InstallApk(Activity context) { this.context = context; } public void installApk(File apkFile) { Intent intent = new Intent(Intent.ACTION_VIEW); if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) { boolean b = context.getPackageManager().canRequestPackageInstalls(); intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(), BuildConfig.APPLICATION_ID+".fileProvider", apkFile); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); context.startActivity(intent); } else { if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) { intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION); Uri contentUri = FileProvider.getUriForFile(context.getApplicationContext(), BuildConfig.APPLICATION_ID+".fileProvider", apkFile); intent.setDataAndType(contentUri, "application/vnd.android.package-archive"); context.startActivity(intent); } else { intent.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive"); intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); context.startActivity(intent); } } } }
头布局
public class DownFileHelper { private static final String TAG = DownFileHelper.class.getSimpleName(); Handler handler; Context mContext; NotificationManager mNotifyManager; Notification.Builder builder; private CommonProgressDialog mDialog; private RemoteViews contentView; public DownFileHelper(Context mContext, Handler handler) { this.handler = handler; this.mContext = mContext; } private void createNotification(final long total, final long current) { mNotifyManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); NotificationCompat.Builder builder = new NotificationCompat.Builder(mContext); builder.setSmallIcon(R.mipmap.ic_launcher);//必须要设置这个属性,否则不显示 contentView = new RemoteViews(mContext.getPackageName(), R.layout.common_progress_dialog); contentView.setProgressBar(R.id.progress, (int) total, (int) current, true); builder.setOngoing(true);//设置左右滑动不能删除 Notification notification = builder.build(); notification.contentView = contentView; mNotifyManager.notify(R.layout.common_progress_dialog, notification);//发送通知 } /** * 下载最新版本的apk * * @param path apk下载地址 */ @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) public void downFile(final String path) { mDialog = new CommonProgressDialog(mContext); mDialog.setMessage("正在下载"); mDialog.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL); mDialog.setMax(100); mDialog.setIndeterminate(true); mDialog.setCancelable(true); mDialog.show(); mNotifyManager = (NotificationManager) mContext.getSystemService(Context.NOTIFICATION_SERVICE); Bitmap btm = BitmapFactory.decodeResource(mContext.getResources(), R.mipmap.ic_launcher);//可以换成你的app的logo if (Build.VERSION.SDK_INT >= 26) {
//创建 通知通道 channelid和channelname是必须的(自己命名就好) @SuppressLint("WrongConstant") NotificationChannel channel = new NotificationChannel("1", "Channel1", NotificationManager.IMPORTANCE_LOW); // channel.enableLights(true);//是否在桌面icon右上角展示小红点 channel.setLightColor(Color.GREEN);//小红点颜色 channel.setShowBadge(true); //是否在久按桌面图标时显示此渠道的通知 channel.enableLights(false); channel.enableVibration(false); // channel.setVibrationPattern(new long[]{0}); channel.setSound(null, null);
mNotifyManager.createNotificationChannel(channel); builder = new Notification.Builder(mContext, "1"); //设置通知显示图标、文字等 builder.setSmallIcon(R.mipmap.ic_launcher)//可以换成你的app的logo .setLargeIcon(btm) .setTicker("正在下载") .setContentTitle("我的app") .setAutoCancel(true) .build(); mNotifyManager.notify(1, builder.build()); } else { builder = new Notification.Builder(mContext); builder.setSmallIcon(R.drawable.ic_danmuku_off)//可以换成你的app的logo .setLargeIcon(btm) .setTicker("正在下载") .setContentTitle("我的app") .setAutoCancel(true)//可以滑动删除通知栏 .build(); mNotifyManager.notify(1, builder.build()); } new Thread() { public void run() { try { URL url = new URL(path); HttpURLConnection con = (HttpURLConnection) url.openConnection(); con.setReadTimeout(5000); con.setConnectTimeout(5000); con.setRequestProperty("Charset", "UTF-8"); con.setRequestMethod("GET"); if (con.getResponseCode() == 200) { int length = con.getContentLength();// 获取文件大小 InputStream is = con.getInputStream(); FileOutputStream fileOutputStream = null; if (is != null) { //对apk进行保存 File file = new File(Environment.getExternalStorageDirectory() .getPath(), "your_app_name.apk"); fileOutputStream = new FileOutputStream(file); byte[] buf = new byte[1024]; int ch; int process = 0; NumberFormat numberFormat = NumberFormat.getInstance(); // 设置精确到小数点后2位 numberFormat.setMaximumFractionDigits(2); String result; while ((ch = is.read(buf)) != -1) { fileOutputStream.write(buf, 0, ch); process += ch; //更新进度条 result = numberFormat.format((float) process / (float) length * 100); mDialog.setProgress((int) ((float) process / (float) length * 100)); builder.setContentText("下载进度:" + result + "%"); builder.setProgress(length, process, false); mNotifyManager.notify(1, builder.build()); } } if (fileOutputStream != null) { fileOutputStream.flush(); fileOutputStream.close(); } //apk下载完成,使用Handler()通知安装apk builder.setProgress(length, length, false); builder.setContentText("已经下载完成"); mNotifyManager.notify(1, builder.build()); mNotifyManager.cancelAll(); handler.sendEmptyMessage(0); } else { Log.e(TAG, "run: ResponseCode"+ con.getResponseCode()); } } catch (Exception e) { e.printStackTrace(); } } }.start(); } }
Dialog
public class CommonProgressDialog extends AlertDialog { private ProgressBar mProgress; private TextView mProgressNumber; private TextView mProgressPercent; private TextView mProgressMessage; private Handler mViewUpdateHandler; private int mMax; private CharSequence mMessage; private boolean mHasStarted; private int mProgressVal; private String TAG = "CommonProgressDialog"; private String mProgressNumberFormat; private NumberFormat mProgressPercentFormat; private TextView tvCancel; public CommonProgressDialog(Context context) { super(context); // TODO Auto-generated constructor stub initFormats(); } @Override protected void onCreate(Bundle savedInstanceState) { // TODO Auto-generated method stub super.onCreate(savedInstanceState); setContentView(R.layout.common_progress_dialog); mProgress = (ProgressBar) findViewById(R.id.progress); mProgressNumber = (TextView) findViewById(R.id.progress_number); mProgressPercent = (TextView) findViewById(R.id.progress_percent); mProgressMessage = (TextView) findViewById(R.id.progress_message); // LayoutInflater inflater = LayoutInflater.from(getContext()); mViewUpdateHandler = new Handler() { @Override public void handleMessage(Message msg) { // TODO Auto-generated method stub super.handleMessage(msg); int progress = mProgress.getProgress(); int max = mProgress.getMax(); double dProgress = (double)progress; double dMax = (double)max; if (mProgressNumberFormat != null) { String format = mProgressNumberFormat; mProgressNumber.setText(String.format(format, dProgress, dMax)); } else { mProgressNumber.setText(""); } if (mProgressPercentFormat != null) { double percent = (double) progress / (double) max; SpannableString tmp = new SpannableString(mProgressPercentFormat.format(percent)); tmp.setSpan(new StyleSpan(android.graphics.Typeface.BOLD), 0, tmp.length(), Spannable.SPAN_EXCLUSIVE_EXCLUSIVE); mProgressPercent.setText(tmp); } else { mProgressPercent.setText(""); } } }; onProgressChanged(); if (mMessage != null) { setMessage(mMessage); } if (mMax > 0) { setMax(mMax); } if (mProgressVal > 0) { setProgress(mProgressVal); } } private void initFormats() { mProgressNumberFormat = "%s/%s"; mProgressPercentFormat = NumberFormat.getPercentInstance(); mProgressPercentFormat.setMaximumFractionDigits(0); } private void onProgressChanged() { mViewUpdateHandler.sendEmptyMessage(0); } public void setProgressStyle(int style) { //mProgressStyle = style; } public int getMax() { if (mProgress != null) { return mProgress.getMax(); } return mMax; } public void setMax(int max) { if (mProgress != null) { mProgress.setMax(max); onProgressChanged(); } else { mMax = max; } } public void setIndeterminate(boolean indeterminate) { if (mProgress != null) { mProgress.setIndeterminate(indeterminate); } } public void setProgress(int value) { if (mHasStarted) { mProgress.setProgress(value); onProgressChanged(); } else { mProgressVal = value; } } @Override public void setMessage(CharSequence message) { // TODO Auto-generated method stub if(mProgressMessage!=null){ mProgressMessage.setText(message); } else{ mMessage = message; } } @Override protected void onStart() { // TODO Auto-generated method stub super.onStart(); mHasStarted = true; } @Override protected void onStop() { // TODO Auto-generated method stub super.onStop(); mHasStarted = false; } }
然后是布局类
activity_update.xml
common_progress_dialog.xml
drawable文件夹资源文件seekbar_style.xml
res内新建一个xml文件夹内设置file_provider.xml
注意path="Android/com.guorentong.learn.myapplication/"要和自己的报名一致
然后清单文件里application标签内设置
在Activity中设置
//版本更新 private String[] permissionStr = new String[]{ Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE }; Handler handler = new Handler() { @Override public void handleMessage(Message msg) { super.handleMessage(msg); switch (msg.what) { case 0: new InstallApk(HomeActivity.this) .installApk(new File(Environment.getExternalStorageDirectory(), "your_app_name.apk")); break; } } }; @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) public void permissionsCheckAndDownload() { if (Build.VERSION.SDK_INT >= 23) { applyPermission(); } else { new DownFileHelper(HomeActivity.this, handler) .downFile(mUrl); } } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) private void applyPermission() { /** * 第 1 步: 检查是否有相应的权限 */ boolean isAllGranted = checkPermissionAllGranted(permissionStr); // 如果这3个权限全都拥有, 则直接执行备份代码 if (!isAllGranted) { /** * 第 2 步: 请求权限 */ // 一次请求多个权限, 如果其他有权限是已经授予的将会自动忽略掉 ActivityCompat.requestPermissions(this, permissionStr,1); } else { new DownFileHelper(HomeActivity.this, handler) .downFile(mUrl); } } /** * 检查是否拥有指定的所有权限 */ private boolean checkPermissionAllGranted(String[] permissions) { for (String permission : permissions) { if (ContextCompat.checkSelfPermission(this, permission) != PackageManager.PERMISSION_GRANTED) { // 只要有一个权限没有被授予, 则直接返回 false return false; } } return true; } @RequiresApi(api = Build.VERSION_CODES.JELLY_BEAN) @Override public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) { super.onRequestPermissionsResult(requestCode, permissions, grantResults); boolean isAllGranted = true; // 判断是否所有的权限都已经授予了 for (int grant : grantResults) { if (grant != PackageManager.PERMISSION_GRANTED) { isAllGranted = false; break; } } if (isAllGranted) { // 如果所有的权限都授予了, 则执行备份代码 new DownFileHelper(HomeActivity.this, handler) .downFile(mUrl); } else { // 弹出对话框告诉用户需要权限的原因, 并引导用户去应用权限管理中手动打开权限按钮 openAppDetails(); } } private void openAppDetails() { AlertDialog.Builder builder = new AlertDialog.Builder(this); builder.setMessage("备份通讯录需要访问 “通讯录” 和 “外部存储器”,请到 “应用信息 -> 权限” 中授予!"); builder.setPositiveButton("去手动授权", new DialogInterface.OnClickListener() { @Override public void onClick(DialogInterface dialog, int which) { Intent intent = new Intent(); intent.setAction(Settings.ACTION_APPLICATION_DETAILS_SETTINGS); intent.addCategory(Intent.CATEGORY_DEFAULT); intent.setData(Uri.parse("package:" + getPackageName())); intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK); intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY); intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS); startActivity(intent); } }); builder.setNegativeButton("取消", null); builder.show(); }
使用的时候判断版本,或者返回字段调用方法
permissionsCheckAndDownload();
就可以了
别忘了设置权限允许未知程序安装
//安装权限
如果需要改变样式可以自己修改
最好 其实 是不用activity开启更新,而采用非绑定式服务。这样后台运行也可以继续下载避免被杀死,防止下载停止。