最近在编写app的升级功能,第一反应就是看看公司的旧项目里有没有相关代码,看看能不能抄过来直接用,结果当然是不行,一是由于需求跟以前有些不同,二是之前的项目可能比较老,没有对7.0进行适配,于是在看完了老的升级代码的基础上,再加上我充分的发挥了码农的搬运精神,东拼西凑终于大致上的满足了需求,于是决定写篇博客,一是做一个记录以后再写这个不用那么费劲,二是希望有相似需求的同学可以少走弯路,废话不多说,先把完整代码贴上来
package com.example.administrator.updateapkdemo;
import android.annotation.TargetApi;
import android.app.Dialog;
import android.app.DownloadManager;
import android.app.ProgressDialog;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.DialogInterface;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.pm.PackageManager;
import android.database.ContentObserver;
import android.database.Cursor;
import android.net.Uri;
import android.os.Build;
import android.os.Environment;
import android.os.Handler;
import android.os.SystemClock;
import android.support.annotation.RequiresApi;
import android.support.v4.content.FileProvider;
import android.support.v7.app.AlertDialog;
import android.support.v7.app.AppCompatActivity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.ProgressBar;
import android.widget.TextView;
import android.widget.Toast;
import java.io.File;
import java.util.Timer;
import java.util.TimerTask;
public class MainActivity extends AppCompatActivity {
private DownloadManager mDownloadManager;
private long mId;
private Dialog mDialog1;
private ProgressBar mProgressBar;
private TextView mPrecent;
private TextView mComplete;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//1、网络获取版本号,跟本地apk版本号比对,如果发现服务器版本号高于本地版本号即弹出对话框,提醒用户更新
new AlertDialog.Builder(MainActivity.this)
.setTitle("版本更新")
.setMessage("发现新的app版本,请及时更新")
.setNegativeButton("暂不更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
dialog.dismiss();
}
})
.setPositiveButton("立即更新", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
//此处使用DownLoadManager开启下载任务
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
DownloadManager.Request request = new DownloadManager.Request(Uri.parse("http://www.wandoujia.com/apps/com.tencent.mm/binding?source=web_inner_referral_binded"));
// 下载过程和下载完成后通知栏有通知消息。
request.setNotificationVisibility(DownloadManager.Request.VISIBILITY_VISIBLE | DownloadManager.Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
request.setTitle("下载");
request.setDescription("apk正在下载");
//设置保存目录 /storage/emulated/0/Android/包名/files/Download
request.setDestinationInExternalFilesDir(MainActivity.this,Environment.DIRECTORY_DOWNLOADS,"jiaogeyi.apk");
mId = mDownloadManager.enqueue(request);
//注册内容观察者,实时显示进度
MyContentObserver downloadChangeObserver = new MyContentObserver(null);
getContentResolver().registerContentObserver(Uri.parse("content://downloads/my_downloads"), true, downloadChangeObserver);
//广播监听下载完成
listener(mId);
//弹出进度条,先隐藏前一个dialog
dialog.dismiss();
//显示进度的对话框
mDialog1 = new Dialog(MainActivity.this, R.style.Theme_AppCompat_Dialog_Alert);
View view = MainActivity.this.getLayoutInflater().inflate(R.layout.progress_dialog, null);
mProgressBar = view.findViewById(R.id.pb);
mPrecent = view.findViewById(R.id.tv_precent);
mDialog1.setContentView(view);
mDialog1.show();
}
})
.create().show();
}
private void listener(final long id) {
//Toast.makeText(MainActivity.this,"XXXX",Toast.LENGTH_SHORT).show();
IntentFilter intentFilter = new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE);
BroadcastReceiver broadcastReceiver = new BroadcastReceiver() {
@Override
public void onReceive(Context context, Intent intent) {
long longExtra = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
if (id == longExtra){
// Uri downloadUri = mDownloadManager.getUriForDownloadedFile(id);
Intent install = new Intent(Intent.ACTION_VIEW);
File apkFile = getExternalFilesDir("DownLoad/jiaogeyi.apk");
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N){
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri uriForFile = FileProvider.getUriForFile(context, "com.example.administrator.updateapkdemo.fileprovider", apkFile);
install.setDataAndType(uriForFile,"application/vnd.android.package-archive");
}else {
install.setDataAndType(Uri.fromFile(apkFile),"application/vnd.android.package-archive");
}
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
startActivity(install);
Toast.makeText(MainActivity.this,"ZZZZ",Toast.LENGTH_SHORT).show();
}
}
};
registerReceiver(broadcastReceiver,intentFilter);
}
class MyContentObserver extends ContentObserver {
public MyContentObserver(Handler handler) {
super(handler);
}
@TargetApi(Build.VERSION_CODES.N)
@Override
public void onChange(boolean selfChange) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(mId);
DownloadManager dManager = (DownloadManager) getSystemService(Context.DOWNLOAD_SERVICE);
final Cursor cursor = dManager.query(query);
if (cursor != null && cursor.moveToFirst()) {
final int totalColumn = cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES);
final int currentColumn = cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR);
int totalSize = cursor.getInt(totalColumn);
int currentSize = cursor.getInt(currentColumn);
float percent = (float) currentSize / (float) totalSize;
float progress = (float) Math.floor(percent * 100);
mPrecent.setText(progress+"%");
mProgressBar.setProgress((int) progress,true);
if (progress == 100)
mDialog1.dismiss();
}
}
}
}
这里需要注意的是7.0之后对文件的权限进行了更严格的限制,需要使用FileProvider来间接的获取文件,所以操作起来自然是要麻烦一些,首先需要做的是在manifests中声明FileProvider
其中authorities是需要注意的地方,这个属性的值最好让他独一无二,所以我这里采用包名加fileprovider来设置,你如果非要设置成xxx.ooo也不是不可以,但是必须和以下这行代码中的第二个参数一致
Uri uriForFile = FileProvider.getUriForFile(context, "com.example.administrator.updateapkdemo.fileprovider", apkFile);
其次就是需要按照下图的方式创建xml文件
这里path报红不用管它,path值为空表示此是映射的是外挂SD卡的根目录(百度说的),java代码中没有的需要注意的地方就这么点,其他的完整代码中都有,当然还有在清单中声明一些权限
最后将运行效果截图贴出来就算完事儿了