美文网首页
系统下载管理器DownloadManager下载,安装apk

系统下载管理器DownloadManager下载,安装apk

作者: 有点健忘 | 来源:发表于2018-11-29 16:12 被阅读59次

    首先学习下FileProvider

    看这里 https://www.jianshu.com/p/e05f35fbb569

    整理下方便用到的时候直接copy,先这样,以后有空再改。

    安装的代码

    权限
    <uses-permission android:name="android.permission.REQUEST_INSTALL_PACKAGES" />

    fun installCheck(context: Context,file: File) {
            if (!file.exists()) {
                return
            }
            //下边这部分不一定需要
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
                if (context.getPackageManager().canRequestPackageInstalls()) {
    
                } else {
                    val intent = Intent(Settings.ACTION_MANAGE_UNKNOWN_APP_SOURCES, Uri.parse("package:" + context.getPackageName()))
                    intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
                    context.startActivity(intent)
                    return
                }
            }
            installApk(context, file)
        }
    
        //安装apk,兼容7.0
        private fun installApk(context: Context, file: File) {
            if (!file.exists()) {
                return
            }
            val intent = Intent(Intent.ACTION_VIEW)
            // 没有在Activity环境下启动Activity,设置下面的标签
            intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
            var uri: Uri
            //版本在7.0以上是不能直接通过uri访问的
            if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.N) {
                //参数1 上下文, 参数2 Provider主机地址和清单文件中保持一致   参数3 共享的文件
                uri = FileProvider.getUriForFile(context, "com.charlie.fileProvider", file)
                //添加这一句表示对目标应用临时授权该Uri所代表的文件
                intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
            } else {
                uri = Uri.fromFile(file)
            }
            intent.setDataAndType(uri, "application/vnd.android.package-archive")
            // intent.setDataAndType(Uri.parse("file://" + file.toString()), "application/vnd.android.package-archive");
    
            context.startActivity(intent)
        }
    

    FileProvider的配置

            <provider
                android:name="android.support.v4.content.FileProvider"
                android:authorities="com.charlie.fileProvider"
                android:exported="false"
                android:grantUriPermissions="true">
                <meta-data
                    android:name="android.support.FILE_PROVIDER_PATHS"
                    android:resource="@xml/file_paths">
                </meta-data>
            </provider>
    

    file_path.xml

    <?xml version="1.0" encoding="utf-8"?>
    <paths xmlns:android="http://schemas.android.com/apk/res/android">
        <!--Context.getFilesDir().-->
        <files-path
            name="filepath"
            path="filepath"/>
    
        <!-- getCacheDir().-->
        <cache-path
            name="cachepath"
            path="cachepath"/>
    
        <!-- Environment.getExternalStorageDirectory().-->
        <external-path
            name="externalpath"
            path="/"/>
    
        <!-- Context.getExternalCacheDir().  -->
        <external-cache-path
            name="externalcachepath"
            path="externalcachepath"/>
    
        <!--Context#getExternalFilesDir(String) Context.getExternalFilesDir(null).   -->
        <external-files-path
            name="externalfilespath"
            path="externalfilespath"/>
    
    </paths>
    

    使用系统下载

    工具类

    import java.io.File;
    import android.app.DownloadManager;
    import android.app.DownloadManager.Request;
    import android.content.ActivityNotFoundException;
    import android.content.Context;
    import android.content.Intent;
    import android.content.SharedPreferences;
    import android.database.Cursor;
    import android.net.Uri;
    import android.os.Environment;
    import android.text.TextUtils;
    import android.util.Log;
    
    public abstract class FileDownManager {
    
        private DownloadManager downloadManager;
        private String fileName;
        private String saveDir;
        public static String DOWNLOAD_SP_NAME = "download_sp_name";
        public Context mContext;
        public abstract Context getContext();
    
        public SharedPreferences getSp() {
            return getContext().getSharedPreferences(DOWNLOAD_SP_NAME, Context.MODE_PRIVATE);
        }
    
        public abstract String savedFileName(String url, String newVersion);
    
        public abstract String savedFileDir();
    
        public File getSavedFile() {
            return new File(Environment.getExternalStorageDirectory(),saveDir+"/"+fileName);
        }
        public static String downloadKey = "downID";
        public static String downloadVersionKey = "version";
    
        public long getDownloadID() {
            return getSp().getLong(downloadKey, -1);
        }
        public String getDownloadVersion() {
            return getSp().getString(downloadVersionKey, "0");
        }
        public void downOrSuccessAction(String url, String newVersion) {
            saveDir = savedFileDir();
            fileName = savedFileName(url, newVersion);
            downloadManager = (DownloadManager) getContext().getSystemService(Context.DOWNLOAD_SERVICE);
            String downVersion = getSp().getString(downloadVersionKey, null);
            if (TextUtils.equals(newVersion, downVersion)) {
                long id = getSp().getLong(downloadKey, -1);
                if (id == -1) {
                    down(url, newVersion);
                } else {
                    query(url, id, newVersion);
                }
            } else {
                getSp().edit().putString(downloadVersionKey, newVersion).commit();
    
                down(url, newVersion);
            }
        }
    
        private void down(String url, String newVersion) {
    
            Uri resource = Uri.parse(url);
            DownloadManager.Request request = new DownloadManager.Request(resource);
            request.setAllowedNetworkTypes(Request.NETWORK_MOBILE | Request.NETWORK_WIFI);
            request.setAllowedOverRoaming(false);
            // set file mime type
            // MimeTypeMap mimeTypeMap = MimeTypeMap.getSingleton();
            // String mimeString =
            // mimeTypeMap.getMimeTypeFromExtension(MimeTypeMap.getFileExtensionFromUrl(url));
            // request.setMimeType(mimeString);
            // show notification on the state bar
            request.setVisibleInDownloadsUi(true);
            request.setNotificationVisibility(Request.VISIBILITY_VISIBLE_NOTIFY_COMPLETED);
            // set the saving file's directory and name
            request.setDestinationInExternalPublicDir(saveDir, fileName);
            requestCustom(request);
            try {
                long id = downloadManager.enqueue(request);
                getSp().edit().putLong(downloadKey, id).commit();
            } catch (Exception e) {
                e.printStackTrace();
                enableDownloadManager(getContext());
            }
        }
    
        public void requestCustom(DownloadManager.Request request) {
    
        }
    
        private void query(String url, long id, String newVersion) {
            System.out.println("query========="+url+"==="+id+"==="+newVersion);
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(id);
            Cursor c = downloadManager.query(query);
            if(c==null) {
                System.out.println("cursor null============");
                redownload(url, id, newVersion);//download record history was cleared
            }
            else if (c.moveToFirst()) {
                int status = c.getInt(c.getColumnIndex(DownloadManager.COLUMN_STATUS));
                switch (status) {
                case DownloadManager.STATUS_PAUSED:
                    Log.v("down", "STATUS_PAUSED");
                case DownloadManager.STATUS_PENDING:
                    Log.v("down", "STATUS_PENDING");
                case DownloadManager.STATUS_RUNNING:
                    Log.v("down", "STATUS_RUNNING");
                    break;
                case DownloadManager.STATUS_SUCCESSFUL:
                    Log.v("down", "STATUS_SUCCESSFUL");
                    String name=c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                    String uri=c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_URI));
                    String uri_d=c.getString(c.getColumnIndex(DownloadManager.COLUMN_URI));//the http url address
                    //name=/storage/emulated/0/justdelete/apkdown/appname1.2.apk
                    //file:///storage/emulated/0/justdelete/apkdown/appname1.2.apk
                    File savedFile=getSavedFile();
                    System.out.println("name="+name+"=="+uri+"==="+uri_d+"====="+savedFile.getAbsolutePath());
                    if (savedFile.exists()) {
                        downloadSuccess(savedFile);
                    } else {
                        System.out.println("file not exist");
                        redownload(url, id, newVersion);
                    }
                    break;
                case DownloadManager.STATUS_FAILED:
                    Log.v("down", "STATUS_FAILED");
                    redownload(url, id, newVersion);
                    break;
                    default:
                        Log.v("down", "STATUS_====="+status);
                        break;
                }
            }else {
                System.out.println("===================cursor size 0");
                redownload(url, id, newVersion);
            }
        }
    
        private void redownload(String url, long id, String newVersion) {
            // if file not exist or download failed,redownload.
            downloadManager.remove(id);
            getSp().edit().remove(downloadKey).commit();
            down(url, newVersion);
        }
    
        protected void downloadSuccess(File downloadFile) {
            System.out.println("downloadfile size======"+downloadFile.length());
        }
    
        public static void enableDownloadManager(Context context) {
            try {
                Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                intent.setData(Uri.parse("package:com.android.providers.downloads"));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                e.printStackTrace();
                Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
        }
    
    }
    

    然后对于不同的下载类型继承工具类,修改key值即可
    如下举了2种例子,一种下载apk,一种下载一个zip文件

    apk类型下载

    import java.io.File;
    import android.content.Context;
    
    public class APKDownloadManager extends FileDownManager{
        public static APKDownloadManager apkDownloadManager;
        public static APKDownloadManager getInstance(Context context) {
            if(apkDownloadManager==null) {
                synchronized (APKDownloadManager.class) {
                    if(apkDownloadManager==null) {
                        apkDownloadManager=new APKDownloadManager();
                    }
                }
            }
            apkDownloadManager.mContext=context;
            return apkDownloadManager;
        }
        public APKDownloadManager() {
            downloadKey="apk_down_id";
            downloadVersionKey="apk_version";
        }
        @Override
        public Context getContext() {
            if(mContext==null) {
                mContext=MyApplication.application;
            }
            return mContext;
        }
    
        @Override
        public String savedFileDir() {
            return "justdelete/apkdown";
        }
    
        @Override
        public String savedFileName(String url, String newVersion) {
            return "appname"+newVersion+".apk";
        }
    
        @Override
        protected void downloadSuccess(File downloadFile) {
            super.downloadSuccess(downloadFile);
            //安裝apk,7.0以上需要权限,并且uri获取也需要fileprovider
            System.out.println("apk download success================="+downloadFile.getAbsolutePath());
        }
    }
    

    zip文件类型下载

    import java.io.File;
    import android.content.Context;
    
    public class MapDownloadManager extends FileDownManager{
        public static MapDownloadManager mapDownloadManager;
        public static MapDownloadManager getInstance(Context context) {
            if(mapDownloadManager==null) {
                synchronized (MapDownloadManager .class) {
                    if(mapDownloadManager==null) {
                        mapDownloadManager=new MapDownloadManager();
                    }
                }
            }
            mapDownloadManager.mContext=context;
            return mapDownloadManager;
        }
    
        public MapDownloadManager() {
            downloadKey="map_down_id";
            downloadVersionKey="map_version";
        }
        @Override
        public Context getContext() {
            if(mContext==null) {
                mContext=MyApplication.application;
            }
            return mContext;
        }
    
        @Override
        public String savedFileName(String url, String newVersion) {
            return "map"+newVersion+".zip";
        }
    
        @Override
        public String savedFileDir() {
            return "justdelete/savedMap";
        }
    
        
        @Override
        protected void downloadSuccess(File downloadFile) {
            //map download success
            System.out.println("map download success=============="+downloadFile.getAbsolutePath());
        }
    }
    
    

    然后是广播

    import java.io.File;
    import java.util.Arrays;
    import android.app.DownloadManager;
    import android.content.BroadcastReceiver;
    import android.content.Context;
    import android.content.Intent;
    import android.database.Cursor;
    import android.text.TextUtils;
    
    public class FileDownloadReceiver extends BroadcastReceiver {
    
        @Override
        public void onReceive(Context context, Intent intent) {
    
            System.out.println("intent======action====" + intent.getAction());
            if (TextUtils.equals(intent.getAction(), DownloadManager.ACTION_DOWNLOAD_COMPLETE)) {
                long reference = intent.getLongExtra(DownloadManager.EXTRA_DOWNLOAD_ID, -1);
                if (reference == -1) {
                    return;
                }
                String filePath = getFilePath(context, reference);
                File file = new File(filePath);
                if (file.exists() && file.length() > 0) {
                    APKDownloadManager apkDownloadManager =  APKDownloadManager.getInstance(context);
                    if (reference == apkDownloadManager.getDownloadID()) {
                        apkDownloadManager.downloadSuccess(file);
                        return;
                    }
                    MapDownloadManager mapDownloadManager = MapDownloadManager.getInstance(context);
                    if (reference == mapDownloadManager.getDownloadID()) {
                        mapDownloadManager.downloadSuccess(file);
                        return;
                    }
                }
    
            } else if (TextUtils.equals(intent.getAction(), DownloadManager.ACTION_NOTIFICATION_CLICKED)) {
    
                long[] ids=intent.getLongArrayExtra(DownloadManager.EXTRA_NOTIFICATION_CLICK_DOWNLOAD_IDS);
                System.out.println("ids=============="+Arrays.toString(ids));
            }
    
        }
    
        private String getFilePath(Context context, long id) {
            DownloadManager.Query query = new DownloadManager.Query();
            query.setFilterById(id);
            Cursor c = ((DownloadManager) context.getSystemService(Context.DOWNLOAD_SERVICE)).query(query);
            if (c != null && c.moveToFirst()) {
                String name = c.getString(c.getColumnIndex(DownloadManager.COLUMN_LOCAL_FILENAME));
                return name;
            }
            return "";
        }
    }
    

    注册广播,权限添加,click那个action测试用的,可以不要

            <uses-permission android:name="android.permission.INTERNET"/>
            <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE"/>
            <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE"/>
            <receiver android:name=".FileDownloadReceiver">
                <intent-filter >
                    <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
                    <action android:name="android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED"/>
                </intent-filter>
                
            </receiver>
    

    下载代码,判断是否需要下载逻辑就看实际情况了

    APKDownloadManager.getInstance(null).downOrSuccessAction("http://d2.eoemarket.com/app0/38
    /38199/apk/1957269.apk?channel_id=426", "1.4");
    

    代码说明

    这个是设置下载的文件保存的文件夹,以及文件的名字的,需要注意第一个参数是sdcard根目录下的目录的名字。你可以随便起个"AAA/BBB/CCC"都可以。

    request.setDestinationInExternalPublicDir(saveDir, fileName);
    

    点到代码里看下,系统建议是用它自带的那些目录,都分门别类了,比如Environment.DIRECTORY_DOWNLOADS就是Download目录了。不过上边也说了,你随便写个目录也可以

     public Request setDestinationInExternalPublicDir(String dirType, String subPath) {
                File file = Environment.getExternalStoragePublicDirectory(dirType);
    
    //goon
         * @param type The type of storage directory to return.  Should be one of
         * {@link #DIRECTORY_MUSIC}, {@link #DIRECTORY_PODCASTS},
         * {@link #DIRECTORY_RINGTONES}, {@link #DIRECTORY_ALARMS},
         * {@link #DIRECTORY_NOTIFICATIONS}, {@link #DIRECTORY_PICTURES},
         * {@link #DIRECTORY_MOVIES}, {@link #DIRECTORY_DOWNLOADS}, or
         * {@link #DIRECTORY_DCIM}.  May not be null.
         * 
         * @return Returns the File path for the directory.  Note that this
         * directory may not yet exist, so you must make sure it exists before
         * using it such as with {@link File#mkdirs File.mkdirs()}.
         */
        public static File getExternalStoragePublicDirectory(String type) {
            throwIfUserRequired();
            return sCurrentUser.buildExternalStoragePublicDirs(type)[0];
        }
    

    打开下载管理器应用界面

    downloadManager.enqueue(request)
    

    上边的代码进行了异常处理,因为如果下载管理器没有启动的话,会抛出异常,我们在这里就调用下边的代码打开下载管理器页面,让用户手动启动.当然中间你可以添加一个弹框,告诉用户点击启动按钮。


    image.png
        /**
         * Start activity to Settings to enable DownloadManager.
         */
        public static void enableDownloadManager(Context context) {
            try {
                Intent intent = new Intent(android.provider.Settings.ACTION_APPLICATION_DETAILS_SETTINGS);
                intent.setData(Uri.parse("package:com.android.providers.downloads"));
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            } catch (ActivityNotFoundException e) {
                e.printStackTrace();
                Intent intent = new Intent(android.provider.Settings.ACTION_MANAGE_APPLICATIONS_SETTINGS);
                intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
                context.startActivity(intent);
            }
        }
    

    系统下载通知的一些参数说明

    还可以监听通知栏的点击事件,添加如下的action即可,这个是文件没下完的时候点击事件,下载完再点击通知栏,系统会自己处理相应的文件的。

    public  final static  String  ACTION_NOTIFICATION_CLICKED  = "android.intent.action.DOWNLOAD_NOTIFICATION_CLICKED";
    

    下载完成的监听

    <action android:name="android.intent.action.DOWNLOAD_COMPLETE"/>
    

    通知栏可见性参数

    request.setNotificationVisibility(Request.VISIBILITY_VISIBLE);
    

    4种:下载中可见,始终不可见,下载中和完成都可见,只有完成的时候可见

    /**
             * This download is visible but only shows in the notifications
             * while it's in progress.
             */
            public static final int VISIBILITY_VISIBLE = 0;
    
            /**
             * This download is visible and shows in the notifications while
             * in progress and after completion.
             */
            public static final int VISIBILITY_VISIBLE_NOTIFY_COMPLETED = 1;
    
            /**
             * This download doesn't show in the UI or in the notifications.
             */
            public static final int VISIBILITY_HIDDEN = 2;
    
            /**
             * This download shows in the notifications after completion ONLY.
             * It is usuable only with
             * {@link DownloadManager#addCompletedDownload(String, String,
             * boolean, String, String, long, boolean)}.
             */
            public static final int VISIBILITY_VISIBLE_NOTIFY_ONLY_COMPLETION = 3;
    
    

    需要注意,设置不可见的时候需要权限

    <uses-permission android:name="android.permission.DOWNLOAD_WITHOUT_NOTIFICATION"/>
    

    题外话

    下边的方法可以跳转到下载历史记录页面

    Intent intent=new Intent(DownloadManager.ACTION_VIEW_DOWNLOADS);
                    startActivity(intent);
    
    image.png

    下载异常

    测试的时候到jira上找个apk地址,结果下载完一直提示我解析失败,我浏览器可以正常下载啊。
    后来换了个浏览器,才发现这地址需要登陆的,我默认的浏览器是登陆状态,所以可以正常下。手机端因为没有登陆,其实下了个html文件回来。

    相关文章

      网友评论

          本文标题:系统下载管理器DownloadManager下载,安装apk

          本文链接:https://www.haomeiwen.com/subject/lnxjmftx.html