版本升级简单思路就是,访问服务器,根据服务器返回数据,是否显示升级的d窗。如果点确定升级,就访问服务器上返回–下载地址的url(okhttp,DownloadManager),下载的进度条显示方式通知栏、d窗进度条百分比、自定义圆环显示。
一、下载Apk的两种方式(okhttp,DownloadManager)
1.DownloadManager
它自带通知栏显示,因此代码比较简单,在调用之前先判断下下载管理器是否被禁用。
public static boolean isDownloadManagerAvailable(Context context) {
int state = context.getPackageManager().getApplicationEnabledSetting("com.android.providers.downloads");
//检测下载管理器是否被禁用
if (state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED
|| state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_USER
|| state == PackageManager.COMPONENT_ENABLED_STATE_DISABLED_UNTIL_USED) {
return false;
}
return true;
}
DownLoadApk这个类下载状态做逻辑处理
public class DownLoadApk {
public static void download(Context context, String url, String title, final String appName) {
//获取存储id
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
long downloadId = sp.getLong(DownloadManager.EXTRA_DOWNLOAD_ID, -1L);
if (downloadId != -1L) {
FileDownloadManager fdm = FileDownloadManager.getInstance(context);
int status = fdm.getDownloadStatus(downloadId);//获取下载状态
switch (status) {
case DownloadManager.STATUS_SUCCESSFUL:
//启动更新界面
Uri uri = fdm.getDownloadUri(downloadId);// 获取保存文件的路径
if (uri != null) {
if (compare(context, uri)) {
//本地的版本大于当前程序的版本直接安装
String path = getDownloadFilePath(context,downloadId);
startInstall(context, path);
return;
} else {
//从FileDownloadManager中移除这个任务
fdm.getDownloadManager().remove(downloadId);
}
}
//重新下载
start(context, url, title, appName);
break;
case DownloadManager.STATUS_FAILED:
//失败
start(context, url, title, appName);
break;
case DownloadManager.STATUS_RUNNING:
LogUtils.d("downloadId=" + downloadId + " ,status = STATUS_RUNNING");
break;
case DownloadManager.STATUS_PENDING:
LogUtils.d("downloadId=" + downloadId + " ,status = STATUS_PENDING");
break;
case DownloadManager.STATUS_PAUSED:
LogUtils.d("downloadId=" + downloadId + " ,status = STATUS_PAUSED");
break;
default:
LogUtils.d("downloadId=" + downloadId + " ,status = " + status);
break;
}
} else {
start(context, url, title, appName);
}
}
private static void start(Context context, String url, String title, String appName) {
long id = FileDownloadManager.getInstance(context).startDownload(context,url, title, "下载完成后点击打开", appName);
SharedPreferences sp = PreferenceManager.getDefaultSharedPreferences(context);
sp.edit().putLong(DownloadManager.EXTRA_DOWNLOAD_ID, id).apply();
LogUtils.d("apk start download" + id);
}
public static void startInstall(Context context, String path) {
Intent intent = new Intent(Intent.ACTION_VIEW);
Uri cDownloadUri = Uri.parse(path);
if (cDownloadUri != null) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
File file = new File(cDownloadUri.getPath());
String authority = context.getPackageName() + ".provider";
Uri contentUri = FileProvider.getUriForFile(context, authority, file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
context.startActivity(intent);
} else {
intent.setDataAndType(cDownloadUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
}
}
/**
* 获取apk程序信息[packageName,versionName...]
*
* @param context Context
* @param path apk path
*/
private static PackageInfo getApkInfo(Context context, String path) {
File file = new File(path);
if (!file.exists()) {
return null;
}
PackageManager pm = context.getPackageManager();
return pm.getPackageArchiveInfo(path, PackageManager.GET_ACTIVITIES);
}
/**
* 下载的apk和当前程序版本比较
*
* @param context Context 当前运行程序的Context
* @param uri apk file's location
* @return 如果当前应用版本小于apk的版本则返回true;如果当前没有安装也返回true
*/
public static boolean compare(Context context, Uri uri) {
String realPathUri = getRealPathFromURI(context, uri);
PackageInfo apkInfo = getApkInfo(context, realPathUri);
if (apkInfo == null) {
return false;
}
try {
PackageInfo currentPackageInfo = context.getPackageManager().getPackageInfo(context.getPackageName(), 0);
//如果下载的apk包名和当前应用不同,则不执行更新 *** 作
if (apkInfo.packageName.equals(currentPackageInfo.packageName)) {
if (apkInfo.versionCode > currentPackageInfo.versionCode) {
return true;
}
}
} catch (PackageManager.NameNotFoundException e) {
e.printStackTrace();
return true; //如果程序没有安装
}
return false;
}
private static String getRealPathFromURI(Context context, Uri contentURI) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
Cursor cursor = context.getContentResolver().query(contentURI, null,
null, null, null);
if (cursor != null) {
try {
cursor.moveToFirst();
int index = cursor.getColumnIndex(MediaStore.MediaColumns.DATA);
return cursor.getString(index);
} catch (Exception e) {
e.printStackTrace();
} finally {
cursor.close();
}
}
} else {
return contentURI.getPath();
}
return null;
}
@SuppressLint("Range")
public static String getDownloadFilePath(Context context, long downloadId) {
//获取下载管理器服务的实例
DownloadManager manager = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
//创建一个查询对象
DownloadManager.Query query = new DownloadManager.Query();
//根据下载id过滤结果
query.setFilterById(downloadId);
//根据状态过滤结果
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
//执行查询
Cursor cursor = manager.query(query);
if (!cursor.moveToFirst()) {
cursor.close();
return null;
}
String downloadFilePath;
// 下载文件在本地保存的路径(Android 7.0以后COLUMN_LOCAL_FILENAME字段被弃用,
// 需要用COLUMN_LOCAL_URI字段来获取本地文件路径的Uri)
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
downloadFilePath = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
} else {
downloadFilePath = cursor.getString(cursor.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
downloadFilePath = downloadFilePath.startsWith("file://") ? downloadFilePath : "file://" + downloadFilePath;
}
//已下载字节大小
long downloadedSoFar = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//下载文件总大小
long totalSize = cursor.getLong(cursor.getColumnIndex(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));
if (downloadedSoFar == totalSize) {
return downloadFilePath;
}
return null;
}
}
需要在清单application中加入
二、使用okhttp下载,自己写d窗或者通知栏显示进度
调用
DownloadUtils.getInstance().download(down_url, getFilePath(MainActivity.this), "QQ.apk", new DownloadUtils.OnDownloadListener() {
其中参数要传下载路径地址,保存文件的路径,文件的名称
/**
* 获得文件存储路径
*/
private static String getFilePath(Context context) {
if (Environment.MEDIA_MOUNTED.equals(Environment.MEDIA_MOUNTED) || !Environment.isExternalStorageRemovable()) {//如果外部储存可用
return context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS).getAbsolutePath() + File.separator;
} else {
return context.getFilesDir().getPath();//直接存在/data/data里,非root手机是看不到的
}
}
下面是通知栏显示或者d窗显示
2.1通知栏显示
private Notification.Builder builder;
private NotificationManager mNotifyMgr;
private static final int NO_3 = 0x3;
//下载的方法
public void downloadApk(final Activity context, String down_url) {
//标题栏
initNotifications();
mNotifyMgr.notify(NO_3, builder.build());
DownloadUtils.getInstance().download(down_url, getFilePath(MainActivity.this), "QQ.apk", new DownloadUtils.OnDownloadListener() {
@Override
public void onDownloadSuccess() {
//标题栏
mNotifyMgr.cancel(NO_3);//设置关闭通知栏
String successDownloadApkPath = getFilePath(MainActivity.this) + "QQ.apk";
installApk1(MainActivity.this, successDownloadApkPath);
}
@Override
public void onDownloading(int progressInfo) {
//标题栏
mNotifyMgr.notify(NO_3, builder.build());
}
@Override
public void onDownloadFailed() {
//标题栏
mNotifyMgr.cancel(NO_3);//设置关闭通知栏
}
});
}
针对通知栏8.0处理
通用安装方法
private void installApk1(Context context, String downloadApkPath) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
//是否有安装位置来源的权限
boolean haveInstallPermission = getPackageManager().canRequestPackageInstalls();
if (haveInstallPermission) {
Log.d("测试", "8.0手机已经拥有安装未知来源应用的权限,直接安装!");
AppUtils.installApk(context, downloadApkPath);
} else {
new CakeResolveDialog(context, "安装应用需要打开安装未知来源应用权限,请去设置中开启权限", () -> {
Uri packageUri = Uri.parse("package:" + context.getPackageName());
Intent intent = new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, packageUri);
startActivityForResult(intent, 10086);
}).show();
}
} else {
AppUtils.installApk(context, downloadApkPath);
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
if (requestCode == 10086) {
Log.d("测试", "设置了安装未知应用后的回调。。。");
String successDownloadApkPath = getFilePath(MainActivity.this) + "QQ.apk";
installApk1(MainActivity.this, successDownloadApkPath);
}
}
//------AppUtils
public class AppUtils {
public static void installApk(Context context, String downloadApk) {
Intent intent = new Intent(Intent.ACTION_VIEW);
File file = new File(downloadApk);
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
String authority = context.getPackageName() + ".provider";
Uri contentUri = FileProvider.getUriForFile(context, authority, file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
} else {
Uri uri = Uri.fromFile(file);
intent.setDataAndType(uri, "application/vnd.android.package-archive");
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
context.startActivity(intent);
}
}
2.2d窗进度条
progressDialog1 = new ProgressDialog(MainActivity.this);
progressDialog1.setProgressStyle(ProgressDialog.STYLE_HORIZONTAL);
progressDialog1.setTitle("正在下载");
progressDialog1.setMessage("请稍后...");
progressDialog1.setProgress(0);
progressDialog1.setMax(100);
progressDialog1.show();
progressDialog1.setCancelable(false);
DownloadUtils.getInstance().download(down_url, getFilePath(MainActivity.this), "QQ.apk", new DownloadUtils.OnDownloadListener() {
@Override
public void onDownloadSuccess() {
if (progressDialog1 != null && progressDialog1.isShowing()) {
progressDialog1.dismiss();
}
String successDownloadApkPath = getFilePath(MainActivity.this) + "QQ.apk";
installApk1(MainActivity.this, successDownloadApkPath);
}
@Override
public void onDownloading(int progressInfo) {
progressDialog1.setProgress(progressInfo);
}
@Override
public void onDownloadFailed() {
progressDialog1.dismiss();
}
});
2.3简易圆环
public class DownloadCircleView extends View {
Paint mBgPaint;
Paint mStepPaint;
Paint mTxtCirclePaint;
Paint mTxtPaint;
int outsideRadius=DpPxUtils.dp2px(100);
int progressWidth =DpPxUtils.dp2px(2);
float progressTextSize = DpPxUtils.dp2px(12);
Context context;
public DownloadCircleView(Context context) {
super(context);
}
public DownloadCircleView(Context context, AttributeSet attrs) {
super(context, attrs);
init(context);
}
public DownloadCircleView(Context context, AttributeSet attrs, int defStyleAttr) {
super(context, attrs, defStyleAttr);
}
@Override
protected void onMeasure(int widthMeasureSpec, int heightMeasureSpec) {
int width;
int height;
int size = MeasureSpec.getSize(widthMeasureSpec);
int mode = MeasureSpec.getMode(widthMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
width = size;
} else {
width = (int) ((2 * outsideRadius) + progressWidth);
}
size = MeasureSpec.getSize(heightMeasureSpec);
mode = MeasureSpec.getMode(heightMeasureSpec);
if (mode == MeasureSpec.EXACTLY) {
height = size;
} else {
height = (int) ((2 * outsideRadius) + progressWidth);
}
setMeasuredDimension(width, height);
}
private void init(Context context) {
int progressColor = Color.parseColor("#FF5836");//进度球颜色
this.context = context;
//灰色背景圆环
mBgPaint = new Paint();
mBgPaint.setStrokeWidth(progressWidth);
mBgPaint.setColor(Color.GRAY);
this.mBgPaint.setAntiAlias(true);
this.mBgPaint.setStyle(Paint.Style.STROKE); //绘制空心圆
//进度圆环
mStepPaint = new Paint();
mStepPaint.setStrokeWidth(progressWidth);
mStepPaint.setColor(progressColor);
this.mStepPaint.setAntiAlias(true);
this.mStepPaint.setStyle(Paint.Style.STROKE); //绘制空心圆
//进度卫星球
mTxtCirclePaint = new Paint();
mTxtCirclePaint.setColor(progressColor);
this.mTxtCirclePaint.setAntiAlias(true);
this.mTxtCirclePaint.setStyle(Paint.Style.FILL); //绘制实心圆
//进度文字5%
mTxtPaint = new Paint();
mTxtPaint.setTextSize(progressTextSize);
mTxtPaint.setColor(Color.WHITE);
this.mTxtPaint.setAntiAlias(true);
}
float maxProgress=100f;
float progress =0f;
public void setProgress(float progress) {
this.progress = progress;
postInvalidate();
}
@Override
protected void onDraw(Canvas canvas) {
super.onDraw(canvas);
//灰色圆圈
int circlePoint = getWidth() / 2;
canvas.drawCircle(circlePoint, circlePoint, outsideRadius, mBgPaint); //画出圆
//进度
RectF oval = new RectF();
oval.left=circlePoint - outsideRadius;
oval.top=circlePoint - outsideRadius;
oval.right=circlePoint + outsideRadius;
oval.bottom=circlePoint + outsideRadius;
float range = 360 * (progress / maxProgress);
canvas.drawArc(oval, -90, range, false, mStepPaint); //根据进度画圆弧
//轨道圆和文字
double x1 = circlePoint + outsideRadius * Math.cos((range-90) * 3.14 / 180);
double y1 = circlePoint + outsideRadius * Math.sin((range-90) * 3.14 / 180);
canvas.drawCircle((float) x1, (float) y1, progressTextSize*1.3f, mTxtCirclePaint);
String txt = (int) progress + "%";
float strwid = mTxtPaint.measureText(txt);//直接返回参数字符串所占用的宽度
canvas.drawText(txt,(float) x1-strwid/2, (float) y1+progressTextSize/2-progressWidth/2,mTxtPaint);
}
}
public class DownloadCircleDialog extends Dialog {
public DownloadCircleDialog(Context context) {
super(context, R.style.Theme_Ios_Dialog);
}
DownloadCircleView circleView;
TextView tvMsg;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.download_circle_dialog_layout);
this.setCancelable(false);//设置点击d出框外部,无法取消对话框
circleView = findViewById(R.id.cir);
tvMsg = findViewById(R.id.tv_msg);
}
public void setProgress(int progress) {
circleView.setProgress(progress);
}
public void setMsg(String msg){
tvMsg.setText(msg);
}
}
只是记录下,写的不完美,如果你看到了这篇文章,有帮助的话,还是很棒的,毕竟资源现在都是要会员。或者有问题请联系。
欢迎分享,转载请注明来源:内存溢出
评论列表(0条)