老大让弄APK直接代码更新,之前没有写过不会,网上溜达了一圈,也抄了一圈,把代码贴出来,下次用的时候可以直接COPY,也希望能帮到没写过的朋友。
流程:
1. 请求后端,判断是否需要更新当前APK。
2. 判断android版本号是否>5.0(Build.VERSION.SDK_INT是否>=23)来决定是否申请读写权限。
3. android版本6.0以上需要用到共享文件(Provider)。
4. 判断android版本是否为8.0来决定是否申请安装APK的权限(8.0的APK安装都要申请)。
5. 下载APK。
6. 安装APK。
1. 这里第一步就不写了,直接请求后端判断即可。
2. 根据android版本申请读写权限(读写权限的onRequestPermissionResult我基本不写,不放心的话可以自己加一下):
// 6.0 以上申请SD卡读写权限
public static void myPermission() {
if (Build.VERSION.SDK_INT >= 23) {
String[] permissions = {Manifest.permission.READ_EXTERNAL_STORAGE, Manifest.permission.WRITE_EXTERNAL_STORAGE};
ActivityCompat.requestPermissions(content, permissions, PERMISSION_WR);
}
}
3. android版本为6.0以上的需要到AndroidManifest申请安装路径,在Application节点下:
<application
...
>
<!--适配android 7.0以及以上更新APK路径-->
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.baiding.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
</application>
3.0. name是固定写法,但不唯一,想知道的可以自己去搜。
3.1. authorities="你的包名.FileProvider。
3.2. exproted指能否被其他应用程序、组件调用或交互,这里false就行,也可以视自己情况而定(大神的解释:https://blog.csdn.net/id19870510/article/details/8141803)。
3.3. grantUriPermission看字面字面意思就是授予读取Uri的权限,一定要设为true,不然你7.0甚至以上的就直接GG了。
3.4. meta-data里的直接copy,跟3.0一样。
3.5. resource先写上="@xml/file_paths",然后在res下建一个名为xml的Directory,再在xml下建一个名为file_paths的Android resource file(看下图)。
3.6. 在file_paths中写下路径名和路径:
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<external-path
name="."
path="baiding" />
name是一个引用字符串,path是文件夹的相对路径,apk存在哪个文件夹下全看path里写的啥,不记得哪里
看到的,有人说name可以空,但是我实时是报错了,然后又看到博客说 . 代表接受所有字符串,果断填了个 .
1. <files-path name="name" path="path" />
物理路径相当于Context.getFilesDir() + /path/。
2.<cache-path name="name" path="path" />
物理路径相当于Context.getCacheDir() + /path/。
3. <external-path name="name" path="path" />
物理路径相当于Environment.getExternalStorageDirectory() + /path/。
4. <external-files-path name="name" path="path" />
物理路径相当于**Context.getExternalFilesDir(String) **+ /path/。
5. <external-cache-path name="name" path="path" />
物理路径相当于Context.getExternalCacheDir() + /path/
</resources>
4. 根据android版本是否>=8.0来决定是否申请安装APK的权限:
//8.0安装新版本APK权限
private void peimissionO() {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {
boolean b = context.getPackageManager().canRequestPackageInstalls(); //检测是否允许安装apk
if (b) {
//安装apk
} else {
//请求安装权限
String[] permission = {Manifest.permission.REQUEST_INSTALL_PACKAGES};
ActivityCompat.requestPermissions((Activity) context, permission, PERMISSION_UP_APK);
}
}
}
//权限
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
switch (requestCode){
case PERMISSION_UP_APK:
if (grantResults.length>0&&grantResults[0]==PackageManager.PERMISSION_GRANTED){
//安装APK
}else {
//跳转到安装未知应用界面
Intent intent=new Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES);
startActivityForResult(intent,PERMISSION_GET_SETTTING);//on line 380
}
break;
}
}
5.下载APK(这里没有做进度条):
//开始下载APK
public void downloadApk() {
Thread downLoadThread = new Thread(mdownApkRunnable2);
downLoadThread.start();
}
private Runnable mdownApkRunnable2 = new Runnable() {
@Override
public void run() {
try {
URL url = new URL(urlAPK);
HttpURLConnection connection = (HttpURLConnection) url.openConnection();
apkFile = new File(Environment.getExternalStorageDirectory().getPath()+"/baiding");
// 网上说在file_path里用files-path的话,对应的java里就得用getFilesDir(),本人吃了大亏,
// 8.0是正常了,但是天杀的5.0居然每次都找不到这个文件,安装的时候直接提示安装包不存在,果断
// 把file_paths里的files换成了external,不知道是我的原因还是咋回事,别问我啥情况,我不知道
//apkFile = new File("data/data/com.baiding/files/baiding/");//5.0no,8.0ok
//apkFile = new File(context.getFilesDir().getPath()+"/baiding");//5.0no,8.0ok
if (!apkFile.exists()) {
apkFile.mkdirs();
}
file = new File(apkFile+"/baiding.apk");
if (!file.exists()) {
file.createNewFile();
}
FileOutputStream fos = new FileOutputStream(file);
InputStream is = connection.getInputStream();
byte[] buf = new byte[1024 * 5];
int len;
while ((len = is.read(buf)) != -1) {
fos.write(buf, 0, len);
}
is.close();
fos.close();
handler.sendEmptyMessage(12);//下载完毕,通知安装
} catch (MalformedURLException e) {
} catch (IOException e) {
//有人跟我说打这个e特别消耗内存
}
}
};
6. 安装APK:
// 更换新的APK(android版本低于8.0)
public void installAPK() {
//跳转安装
Intent intent = new Intent(Intent.ACTION_VIEW);
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.O) {// 8.0
peimissionO();//检查安装权限
} else {
if (Build.VERSION.SDK_INT == Build.VERSION_CODES.N) {// 7.0
intent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
//第二个参数是你的包名+.FileProvider(你也可以直接去AndroidMenifest中把你刚才写的provider的authorities拷贝过来,Fileprovider开头大小写不限)
Uri contentUri = FileProvider.getUriForFile(context, "com.baiding.Fileprovider", file);
intent.setDataAndType(contentUri, "application/vnd.android.package-archive");
} else {//7.0以下
intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
//下面这俩,反正我的是不奏效
//intent.setDataAndType(Uri.pars("file:"+"data/data/com.baiding/files/baiding/"),
// "application/vnd.android.package-archive");
//intent.setDataAndType(Uri.fromFile(file), "application/vnd.android.package-archive");
}
context.startActivity(intent);
}
}
END...
注: 1.自己看博客的时候没看明白,导致自己APK明明已经下载成功,但是怎么都解析失败,其实就错在xml的file_path里的 path,比如你用的是external-path,在创建文件的时候就一定要把path加进去(第一次做,血的教训):
File file= new File(Environment.getExternalStorageDirectory().getPath()+"/path里的那几个字母");
2.如果你xml的file_path用的是files-path,完事你走到安装apk这一步了,老是提示什么文件夹不存在,程序包不存在啥啥啥的,趁时间还早,试试external-path或者其他的吧,本人愣是在files-path耗了N个小时后受不了才换的,瞬间啥病都没了,唉。