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

 强制升级:

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> {

    @Override
    public void onSubscribe(Disposable d) {

    }

    @Override
    public void onNext(Integer progress){//设置进度
    }

    @Override
    public void onError(Throwable throwable) {
        throwable.printStackTrace();
        Toast.makeText(MainActivity.this, "出错", Toast.LENGTH_SHORT).show();
    }

    @Override
    public 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存储权限要申请,解决拒绝后的闪退事件。

权限判断
@Override
public 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);
}
 
 





猜你喜欢

转载自blog.csdn.net/nvcxy_1225/article/details/78606528
今日推荐