Android 在线下载更新App 下载完成安装APK(兼容Android7.0)

先上图:


首先对android7.0的打开文件方式进行适配

使用FileProvider

第一步:
在AndroidManifest.xml清单文件中注册provider,因为provider也是Android四大组件之一,可以简单把它理解为向外提供数据的组件,这种组件在实际开发中用的频率并不高,四大组件都可以在清单文件中进行配置。

<application
   ...>
    <provider
        android:name="android.support.v4.content.FileProvider"
        android:authorities="com.example.dl.install"
        android:grantUriPermissions="true"
        android:exported="false">
        <!--元数据-->
        <meta-data
            android:name="android.support.FILE_PROVIDER_PATHS"
            android:resource="@xml/file_paths" />
    </provider>
</application>

注意:

  • exported:要求必须为false,为true则会报安全异常。
  • grantUriPermissions:true,表示授予 URI 临时访问权限。
  • authorities 组件标识,按照江湖规矩,都以包名开头,避免和其它应用发生冲突。
第二步:指定共享的目录
上面配置文件中  android:resource="@xml/file_paths"  指的是当前组件引用  res/xml/file_paths.xml  这个文件。
我们需要在资源(res)目录下创建一个xml目录,然后创建一个名为“file_paths”(名字可以随便起,只要和在manifest注册的provider所引用的resource保持一致即可)的资源文件,内容如下:

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

<files-path/>代表的根目录: Context.getFilesDir()
<external-path/>代表的根目录: Environment.getExternalStorageDirectory()
<cache-path/>代表的根目录: getCacheDir()

上述代码中path="",是有特殊意义的,它代码根目录,也就是说你可以向其它的应用共享根目录及其子目录下任何一个文件了。

如果你将path设为path="pictures",那么它代表着根目录下的pictures目录(eg:/storage/emulated/0/pictures),如果你向其它应用分享pictures目录范围之外的文件是不行的。

第三步:使用FileProvider
上述准备工作做完之后,现在我们就可以使用FileProvider了。会在下个代码块中注释中具体解释



下面是下载安装的具体逻辑

首先在服务中创建DownloadManager

public class DownloadService extends Service {
    private DownloadFinishReceiver mReceiver;
    public DownloadService() {
    }

    @Override
    public void onCreate() {
        super.onCreate();

        //注册下载完成的广播
        mReceiver = new DownloadFinishReceiver();
        registerReceiver(mReceiver, new IntentFilter(DownloadManager.ACTION_DOWNLOAD_COMPLETE));
    }

    @Override
    public IBinder onBind(Intent intent) {
        return new DownBinder();
    }

    class DownBinder extends Binder{
        public void startDownload (String downUrl) {
            //删除已经存在的apk包
            File apkFile = new File(DownloadService.this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "小熊.apk");
            if (apkFile.exists()) {
                apkFile.delete();
            }
            //初始化DownloadManager并开始下载
            DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl));
            File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"小熊.apk");
            request.setDestinationUri(Uri.fromFile(file));
            DownloadManager mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE);
            mDownloadManager.enqueue(request);
        }
    }

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

        @Override
        public void onReceive(Context context, Intent intent) {
            //Android获取一个用于打开APK文件的intent
            Intent intent1 = new Intent(Intent.ACTION_VIEW);
            // 由于没有在Activity环境下启动Activity,设置下面的标签
            intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK);
            if(Build.VERSION.SDK_INT>=24) { //判读版本是否在7.0以上
                //参数1 上下文, 参数2 Provider主机地址 和配置文件中保持一致   参数3  共享的文件
                Uri apkUri =
                        FileProvider.getUriForFile(DownloadService.this, "com.example.dl.install",
                                new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"小熊.apk"));
                //添加这一句表示对目标应用临时授权该Uri所代表的文件
                intent1.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
                intent1.setDataAndType(apkUri, "application/vnd.android.package-archive");
            }else{
                intent1.setDataAndType(Uri.fromFile(new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"小熊.apk")),
                        "application/vnd.android.package-archive");
            }
            DownloadService.this.startActivity(intent1);
        }
    }

    @Override
    public void onDestroy() {
        super.onDestroy();
        unregisterReceiver(mReceiver);
    }
}

然后在anctivity中与服务bind绑定 布局文件只有一个按钮来模拟

public class MainActivity extends AppCompatActivity implements View.OnClickListener {

    private Button btn;
    private DownloadService.DownBinder binder;

    private ServiceConnection connection = new ServiceConnection() {
        @Override
        public void onServiceConnected(ComponentName name, IBinder service) {
           binder = (DownloadService.DownBinder) service;
        }

        @Override
        public void onServiceDisconnected(ComponentName name) {

        }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        initView();

        //与服务连接
        Intent intent = new Intent(MainActivity.this,DownloadService.class);
        startService(intent);
        bindService(intent,connection,BIND_AUTO_CREATE);

    }

    private void initView() {
        btn = (Button) findViewById(R.id.btn);

        btn.setOnClickListener(this);
    }

    @Override
    public void onClick(View v) {
        switch (v.getId()) {
            case R.id.btn:
                binder.startDownload("http://cdn.xiaoxiongyouhao.com/apps/androilas.apk");
                break;
        }
    }
}

最后添加权限 动态权限前文有使用介绍 这里我没有使用动态权限

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



  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 3
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值