1.对比版本号,校验是否需要更新(省略)
2.弹窗提示
private void checkUpdate() {
//TODO 如果版本号一致,清除缓存的 download apk的id
// SPUtils.putLong(this, DownloadedApkUtlis.DOWNLOAD_ID, -1);
showUpdateDialog();
}
private void showUpdateDialog() {
AlertDialog alertDialog = new AlertDialog.Builder(this).create();
alertDialog.setCancelable(false);
alertDialog.setTitle("发现新版本");
alertDialog.setMessage("为了您更好的体验,请更新最新版本");
DialogInterface.OnClickListener listener = null;
alertDialog.setButton(DialogInterface.BUTTON_NEGATIVE, "取消", listener);
alertDialog.setButton(DialogInterface.BUTTON_POSITIVE, "立即下载", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialogInterface, int i) {
downLoadApk();
}
});
alertDialog.show();
}
3.下载apk(已经下载过,未安装直接安装)
//------------------------------------------------------
import android.app.DownloadManager;
import android.content.Context;
import android.content.DialogInterface;
import android.content.IntentFilter;
import android.database.ContentObserver;
import android.database.Cursor;
import android.graphics.drawable.Drawable;
import android.net.ConnectivityManager;
import android.net.Uri;
import android.net.wifi.WifiManager;
import android.os.Bundle;
import android.os.Environment;
import android.os.Handler;
import android.support.v7.app.AlertDialog;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
//------------------------------------------------------
private DownloadChangeObserver downloadObserver;
private long lastDownloadId = 0;
//"content://downloads/my_downloads"必须这样写不可更改
public static final Uri CONTENT_URI = Uri.parse("content://downloads/my_downloads");
private String netUrl = "http://toppic.oss.com/weixin.apk";
private void downLoadApk() {
//1.得到下载对象
DownloadManager dowanloadmanager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
//是否有缓存
long spDownloadId = (long) SPUtils.get(this, DownloadedApkUtlis.DOWNLOAD_ID, (long)-1);
/*
下载管理器中有很多下载项,怎么知道一个资源已经下载过,避免重复下载呢?
我的项目中的需求就是apk更新下载,用户点击更新确定按钮,第一次是直接下载,
后面如果用户连续点击更新确定按钮,就不要重复下载了。
可以看出来查询和操作数据库查询一样的
*/
if (spDownloadId > 0) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(spDownloadId);
Cursor cursor = dowanloadmanager.query(query);
if (!cursor.moveToFirst()) {// 没有记录
Log.d("mylog", "downLoadApk: 没有记录 ");
} else {
//有记录
InstallApkUtlis.toInstallApk(this); //有记录,直接安装
return;
}
}
//2.创建下载请求对象,并且把下载的地址放进去
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(netUrl));
//3.给下载的文件指定路径
request.setDestinationInExternalFilesDir(this, Environment.DIRECTORY_DOWNLOADS, "xfzs.apk");
//4.设置显示在文件下载Notification(通知栏)中显示的文字。6.0的手机Description不显示
request.setTitle("YC");
request.setDescription("正在下载");
//5更改服务器返回的minetype为android包类型
request.setMimeType("application/vnd.android.package-archive");
//6.设置在什么连接状态下执行下载操作
request.setAllowedNetworkTypes(DownloadManager.Request.NETWORK_MOBILE | DownloadManager.Request.NETWORK_WIFI);
//7. 设置为可被媒体扫描器找到
request.allowScanningByMediaScanner();
//8. 设置为可见和可管理
request.setVisibleInDownloadsUi(true);
lastDownloadId = dowanloadmanager.enqueue(request);
//9.保存id到缓存
SPUtils.putLong(this, DownloadedApkUtlis.DOWNLOAD_ID, lastDownloadId);
}
4.安装的工具类
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.os.Build;
import android.support.v4.content.FileProvider;
import com.yc.love.BuildConfig;
import com.yc.love.model.util.DownloadedApkUtlis;
import java.io.File;
/**
* Created by mayn on 2019/5/20.
*/
public class InstallApkUtlis {
public static void toInstallApk(Context context) {
Intent install = new Intent(Intent.ACTION_VIEW);
File apkFile = DownloadedApkUtlis.queryDownloadedApk(context);
//判断是否是AndroidN以及更高的版本
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
install.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
Uri contentUri = FileProvider.getUriForFile(context, BuildConfig.APPLICATION_ID + ".fileProvider", apkFile);
install.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {
install.setDataAndType(Uri.fromFile(apkFile), "application/vnd.android.package-archive");
// install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
}
install.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
context.startActivity(install);
}
}
5.通过广播接收者监听系统下载apk已完成
import android.annotation.SuppressLint;
import android.app.DownloadManager;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import com.yc.love.model.util.DownloadedApkUtlis;
import com.yc.love.model.util.SPUtils;
import com.yc.love.utils.InstallApkUtlis;
/**
* Created by mayn on 2019/5/20.
*/
public class UpdataBroadcastReceiver extends BroadcastReceiver {
@SuppressLint("NewApi")
public void onReceive(Context context, Intent intent) {
long downLoadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
long cacheDownLoadId = (long) SPUtils.get(context,DownloadedApkUtlis.DOWNLOAD_ID,(long)-1);
if (cacheDownLoadId == downLoadId) {
InstallApkUtlis.toInstallApk(context);
}
}
}
别忘了去清单文件注册BroadcastReceiver
<receiver android:name=".receiver.UpdataBroadcastReceiver">
<intent-filter>
<action android:name="android.intent.action.DOWNLOAD_COMPLETE" />
</intent-filter>
</receiver>
6.查询下载的apk的工具类
import android.app.DownloadManager;
import android.content.Context;
import android.database.Cursor;
import android.net.Uri;
import android.text.TextUtils;
import java.io.File;
/**
* Created by mayn on 2019/5/20.
*/
public class DownloadedApkUtlis {
public static final String DOWNLOAD_ID = "download_id";
//通过downLoadId查询下载的apk,解决6.0以后安装的问题
public static File queryDownloadedApk(Context context) {
File targetApkFile = null;
DownloadManager downloader = (DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE);
long downloadId = (long) SPUtils.get(context, DOWNLOAD_ID, (long)-1);
if (downloadId != -1) {
DownloadManager.Query query = new DownloadManager.Query();
query.setFilterById(downloadId);
query.setFilterByStatus(DownloadManager.STATUS_SUCCESSFUL);
Cursor cur = downloader.query(query);
if (cur != null) {
if (cur.moveToFirst()) {
String uriString = cur.getString(cur.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
if (!TextUtils.isEmpty(uriString)) {
targetApkFile = new File(Uri.parse(uriString).getPath());
}
}
cur.close();
}
}
return targetApkFile;
}
}
7.在清单文件配置FileProvider
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="you_package.fileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
res/xml/file_paths文件
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path path="Android/data/you_包名/" name="files_root" />
<external-path path="." name="external_storage_root" />
</paths>
截个图
SPUtils工具类
import android.content.Context;
import android.content.SharedPreferences;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;
/**
* Created by Administrator on 2017/9/15.
*/
public class SPUtils {
/**
* 保存数据的方法,我们需要拿到保存数据的具体类型,然后根据类型调用不同的保存方法
*
* @param context
* @param key
* @param object
*/
public static void put(Context context, String key, Object object) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
if (object instanceof String) {
editor.putString(key, (String) object);
} else if (object instanceof Integer) {
editor.putInt(key, (Integer) object);
} else if (object instanceof Boolean) {
editor.putBoolean(key, (Boolean) object);
} else if (object instanceof Float) {
editor.putFloat(key, (Float) object);
} else if (object instanceof Long) {
editor.putLong(key, (Long) object);
} else {
editor.putString(key, object.toString());
}
SharedPreferencesCompat.apply(editor);
}
public static void putLong(Context context, String key, long longData) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.putLong(key, longData);
SharedPreferencesCompat.apply(editor);
}
/**
* 得到保存数据的方法,我们根据默认值得到保存的数据的具体类型,然后调用相对于的方法获取值
*
* @param context
* @param key
* @param defaultObject
* @return
*/
public static Object get(Context context, String key, Object defaultObject) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
if (defaultObject instanceof String) {
return sp.getString(key, (String) defaultObject);
} else if (defaultObject instanceof Integer) {
return sp.getInt(key, (Integer) defaultObject);
} else if (defaultObject instanceof Boolean) {
return sp.getBoolean(key, (Boolean) defaultObject);
} else if (defaultObject instanceof Float) {
return sp.getFloat(key, (Float) defaultObject);
} else if (defaultObject instanceof Long) {
return sp.getLong(key, (Long) defaultObject);
}
return null;
}
/**
* 移除某个key值已经对应的值
*
* @param context
* @param key
*/
public static void remove(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.remove(key);
SharedPreferencesCompat.apply(editor);
}
/**
* 清除所有数据
*
* @param context
*/
public static void clear(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
SharedPreferences.Editor editor = sp.edit();
editor.clear();
SharedPreferencesCompat.apply(editor);
}
/**
* 查询某个key是否已经存在
*
* @param context
* @param key
* @return
*/
public static boolean contains(Context context, String key) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.contains(key);
}
/**
* 返回所有的键值对
*
* @param context
* @return
*/
public static Map<String, ?> getAll(Context context) {
SharedPreferences sp = context.getSharedPreferences(FILE_NAME,
Context.MODE_PRIVATE);
return sp.getAll();
}
/**
* 创建一个解决SharedPreferencesCompat.apply方法的一个兼容类
*
* @author zhy
*/
private static class SharedPreferencesCompat {
private static final Method sApplyMethod = findApplyMethod();
/**
* 反射查找apply的方法
*
* @return
*/
@SuppressWarnings({"unchecked", "rawtypes"})
private static Method findApplyMethod() {
try {
Class clz = SharedPreferences.Editor.class;
return clz.getMethod("apply");
} catch (NoSuchMethodException e) {
}
return null;
}
/**
* 如果找到则使用apply执行,否则使用commit
*
* @param editor
*/
public static void apply(SharedPreferences.Editor editor) {
try {
if (sApplyMethod != null) {
sApplyMethod.invoke(editor);
return;
}
} catch (IllegalArgumentException e) {
} catch (IllegalAccessException e) {
} catch (InvocationTargetException e) {
}
editor.commit();
}
}
/**
* 保存在手机里面的文件名
*/
private static final String FILE_NAME = "share_data";
}