您的位置:首页 > 移动开发

安卓 app 本地升级下载后自动安装(小米手机安装包解析失败问题)

2017-11-22 18:14 766 查看
 强制升级:1.新建服务
package com.jy.mango.project.service;

import android.app.DownloadManager;
import android.app.Service;
import android.content.BroadcastReceiver;
import android.content.ContentResolver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.database.Cursor;
import android.net.Uri;
import android.os.Binder;
import android.os.Environment;
import android.os.IBinder;
import android.provider.MediaStore;
import android.support.annotation.NonNull;
import android.support.annotation.Nullable;
import android.util.Log;
import android.util.LongSparseArray;
import android.webkit.MimeTypeMap;

import com.jy.mango.project.application.installutils.IOUtils;
import com.jy.mango.project.application.installutils.InstallUtil;
import com.jy.mango.project.application.installutils.SystemManager;
import com.jy.mango.project.utils.T;

import java.io.File;
import java.io.IOException;
import java.net.URI;
import java.net.URISyntaxException;

/**
* Created by mango on 2017/11/6.
*/

public class UpdateService extends Service {

private DownloadManager mDownloadManager;
private DownloadBinder mBinder = new DownloadBinder();
private LongSparseArray<String> mApkPaths;
private DownloadFinishReceiver mReceiver;

@Override
public void onCreate() {
super.onCreate();
mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
mApkPaths = new LongSparseArray<>();
//注册下载完成的广播
mReceiver = new DownloadFinishReceiver();
registerReceiver(mReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
}

@Nullable
@Override
public IBinder onBind(Intent intent) {
return mBinder;
}

@Override
public void onDestroy() {
unregisterReceiver(mReceiver);//取消注册广播接收者
super.onDestroy();
}

public class DownloadBinder extends Binder {
/**
* 下载
* @param apkUrl 下载的url
*/
public long startDownload(String apkUrl){
//点击下载
//删除原有的APK
IOUtils.clearApk(UpdateService.this,"app.apk");
//使用DownLoadManager来下载
DownloadManager.Request request = new DownloadManager.Request(Uri.parse(apkUrl));
//将文件下载到自己的Download文件夹下,必须是External的
//这是DownloadManager的限制
File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "app.apk");
request.setDestinationUri(Uri.fromFile(file));

//添加请求 开始下载
long downloadId = mDownloadManager.enqueue(request);
Log.d("DownloadBinder", file.getAbsolutePath());
mApkPaths.put(downloadId,file.getAbsolutePath());
return downloadId;
}

/**
* 获取进度信息
* @param downloadId 要获取下载的id
* @return 进度信息 max-100
*/
public int getProgress(long downloadId) {
//查询进度
DownloadManager.Query query = new DownloadManager.Query()
.setFilterById(downloadId);
Cursor cursor = null;
int progress = 0;
try {
cursor = mDownloadManager.query(query);//获得游标
if (cursor != null && cursor.moveToFirst()) {
//当前的下载量
int downloadSoFar = cursor.getInt(cursor.getColumnIndex(DownloadManager.COLUMN_BYTES_DOWNLOADED_SO_FAR));
//文件总大小
int totalBytes = cursor.getInt(cursor.getColumnIndexOrThrow(DownloadManager.COLUMN_TOTAL_SIZE_BYTES));

progress = (int) (downloadSoFar * 1.0f / totalBytes * 100);
}
} finally {
if (cursor != null) {

cursor.close();
}
}

return progress;
}

}

//下载完成的广播
private class DownloadFinishReceiver extends BroadcastReceiver{

@Override
public void onReceive(Context context, Intent intent) {
//下载完成的广播接收者
long completeDownloadId = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
String apkPath = mApkPaths.get(completeDownloadId);
Log.d("DownloadFinishReceiver", apkPath);
if (!apkPath.isEmpty()){
SystemManager.setPermission(apkPath);//提升读写权限,否则可能出现解析异常
InstallUtil.install(context,apkPath);
}else {
Log.e("DownloadFinishReceiver", "apkPath is null");
}
}
}

}
2.配置manifest文件
<service android:name=".UpdateService"/>

<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="包名"
android:grantUriPermissions="true"
android:exported="false">
<!--元数据-->
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_path" />
</provider>
3.指定path在res下新建文件夹xml  新建xml文件命名为path
<?xml version="1.0" encoding="utf-8"?>
<resources xmlns:android="http://schemas.android.com/apk/res/android">
<paths>
<external-path path="" name="download"/>
</paths>
</resources>
4. 启动服务下载文件
private UpdateService.DownloadBinder mDownloadBinder;
private ServiceConnection mConnection = new ServiceConnection() {
@Override
public void onServiceConnected(ComponentName name, IBinder service) {
mDownloadBinder = (UpdateService.DownloadBinder) service;
}

@Override
public void onServiceDisconnected(ComponentName name) {
mDownloadBinder = null;
}
};
启动服务
Intent intent = new Intent(this, UpdateService.class);
startService(intent);
bindService(intent, mConnection, BIND_AUTO_CREATE);//绑定服务
开始下载
if (mDownloadBinder != null) {long downloadId = mDownloadBinder.startDownload(serviceUrl);startCheckProgress(downloadId);dialog.dismiss();}
监听下载
//开始监听进度private void startCheckProgress(long downloadId) {Observable.interval(100, 200, TimeUnit.MILLISECONDS, Schedulers.io())//无限轮询,准备查询进度,在io线程执行.filter(times -> mDownloadBinder != null).map(i -> mDownloadBinder.getProgress(downloadId))//获得下载进度.takeUntil(progress -> progress >= 100)//返回true就停止了,当进度>=100就是下载完成了.distinct()//去重复.subscribeOn(Schedulers.io()).observeOn(AndroidSchedulers.mainThread()).subscribe(new ProgressObserver());}//观察者private class ProgressObserver implements Observer<Integer> {@Overridepublic void onSubscribe(Disposable d) {}@Overridepublic void onNext(Integer progress){//设置进度}@Overridepublic void onError(Throwable throwable) {throwable.printStackTrace();Toast.makeText(MainActivity.this, "出错", Toast.LENGTH_SHORT).show();}@Overridepublic void onComplete() {Toast.makeText(MainActivity.this, "下载完成", Toast.LENGTH_SHORT).show();}}
5. 修改文件权限,并且在下载完成后删除文件,关闭文件流
 class SystemManager {/*** 应用程序运行命令获取 Root权限,设备必须已破解(获得ROOT权限)** @param command 命令:String apkRoot="chmod 777 "+getPackageCodePath();* @return  0 命令执行成功*/public static int RootCommand(String command) {Process process = null;DataOutputStream os = null;try {process = Runtime.getRuntime().exec("su");os = new DataOutputStream(process.getOutputStream());os.writeBytes(command + "\n");os.writeBytes("exit\n");os.flush();int i = process.waitFor();Log.d("SystemManager", "i:" + i);return i;} catch (Exception e) {Log.d("SystemManager", e.getMessage());return -1;} finally {try {if (os != null) {os.close();}process.destroy();} catch (Exception e) {}}}/*** 提升读写权限* @param filePath 文件路径* @return* @throws IOException*/public static void setPermission(String filePath)  {String command = "chmod " + "777" + " " + filePath;Runtime runtime = Runtime.getRuntime();try {runtime.exec(command);} catch (IOException e) {e.printStackTrace();}}
关闭文件流及成功后删除APK文件
IOUtils {public static void closeIO(Closeable... closeables) {if (closeables != null) {for (Closeable closeable : closeables) {if (closeable != null) {try {closeable.close();} catch (IOException e) {e.printStackTrace();}}}}}/*** 删除之前的apk** @param apkName apk名字* @return*/public static File clearApk(Context context, String apkName) {File apkFile = new File(context.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), apkName);if (apkFile.exists()) {apkFile.delete();}return apkFile;}}
6.OK啦!判断权限,并请求权限,6.0存储权限要申请,解决拒绝后的闪退事件。
权限判断
@Overridepublic void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults){if (requestCode == MY_PERMISSIONS_REQUEST_CALL_PHONE) {if (grantResults[0] == PackageManager.PERMISSION_GRANTED){if (mDownloadBinder != null) {long downloadId = mDownloadBinder.startDownload(serviceUrl);startCheckProgress(downloadId);}} else{T.showLong("该应用已被禁止存储权限" +"\n请在设置>权限管理中授权");alertDialog.show();}return;}super.onRequestPermissionsResult(requestCode, permissions, grantResults);}

                                            
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  android
相关文章推荐