Firstly, it adapts the open file mode of Android 7.0
Using FileProvider
Step one:Register provider in Android Manifest. XML manifest file, because provider is also one of the four components of Android. It can be simply understood as a component that provides data to the outside world. This component is not frequently used in actual development, and the four components can be configured in the manifest file.
<application ...> <provider android:name="android.support.v4.content.FileProvider" android:authorities="com.example.dl.install" android:grantUriPermissions="true" android:exported="false"> <!--metadata--> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider> </application>
Be careful:
- Export: Requirements must be false and security exceptions will be reported for true.
- Grant UriPermissions: true, indicating grant URI temporary access rights.
- The authorities'component identification, according to the rules of the river and lake, starts with the package name to avoid conflicts with other applications.
Step 2: Specify shared directories
In the configuration file above, android:resource="@xml/file_paths" refers to the current component referring to the file res/xml/file_paths.xml.
In the configuration file above, android:resource="@xml/file_paths" refers to the current component referring to the file res/xml/file_paths.xml.
We need to create an xml directory under the resource (res) directory and then create a resource file named "file_paths" (the name can be arbitrary, as long as it is consistent with the resource referenced by the provider registered with manifest), which reads as follows:
<?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>
The root directory represented by <files-path/>: Context.getFilesDir()
The root directory represented by <external-path/>: Environment.getExternal Storage Directory ()
The root directory represented by <cache-path/>: getCacheDir()
The root directory represented by <external-path/>: Environment.getExternal Storage Directory ()
The root directory represented by <cache-path/>: getCacheDir()
The path = "" in the above code is of special significance. It is the code root directory, which means that you can share any file in the root directory and its subdirectories with other applications.
If you set path to path="pictures", it represents the pictures directory in the root directory (eg:/storage/emulated/0/pictures). If you share files outside the scope of the pictures directory with other applications, it is not possible.
If you set path to path="pictures", it represents the pictures directory in the root directory (eg:/storage/emulated/0/pictures). If you share files outside the scope of the pictures directory with other applications, it is not possible.
Step 3: Use FileProvider
Now that we've done the above, we can use FileProvider. It will be explained in the comments in the next block of code.
Now that we've done the above, we can use FileProvider. It will be explained in the comments in the next block of code.
Here's the download and installation logic
First create the Download Manager in the service
public class DownloadService extends Service { private DownloadFinishReceiver mReceiver; public DownloadService() { } @Override public void onCreate() { super.onCreate(); //Register and download completed broadcasting 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) { //Delete existing apk packages File apkFile = new File(DownloadService.this.getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS), "Little bear.apk"); if (apkFile.exists()) { apkFile.delete(); } //Initialize Download Manager and start downloading DownloadManager.Request request = new DownloadManager.Request(Uri.parse(downUrl)); File file = new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"Little bear.apk"); request.setDestinationUri(Uri.fromFile(file)); DownloadManager mDownloadManager = (DownloadManager) getSystemService(DOWNLOAD_SERVICE); mDownloadManager.enqueue(request); } } //Download completed broadcast private class DownloadFinishReceiver extends BroadcastReceiver { @Override public void onReceive(Context context, Intent intent) { //Android gets an intent for opening APK files Intent intent1 = new Intent(Intent.ACTION_VIEW); // Since Activity is not started in the Activity environment, set the following label intent1.setFlags(Intent.FLAG_ACTIVITY_NEW_TASK); if(Build.VERSION.SDK_INT>=24) { //Is the interpretation version above 7.0? //Parametric 1 context, Parametric 2 Provider host address and file shared in configuration file with consistent parameter 3 Uri apkUri = FileProvider.getUriForFile(DownloadService.this, "com.example.dl.install", new File(getExternalFilesDir(Environment.DIRECTORY_DOWNLOADS),"Little bear.apk")); //Add this sentence to indicate that the file represented by the Uri is temporarily authorized for the target application 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),"Little bear.apk")), "application/vnd.android.package-archive"); } DownloadService.this.startActivity(intent1); } } @Override public void onDestroy() { super.onDestroy(); unregisterReceiver(mReceiver); } }
Then in anctivity, there is only one button to simulate the binding layout file with service 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(); //Connecting to services 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; } } }
Finally, add permission dynamic permission. I did not use dynamic permission here.
<uses-permission android:name="android.permission.INTERNET"/> <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
Below is the next rendering: