需求:假如有2个apk,一个客户端(client),一个服务端(service),客户端请求服务端so库文件,服务端分享so库给客户端,客户端进行加载,直接撸代码。
1: 设置FileProvider
为了给应用程序定义一个FileProvider,需要在Manifest清单文件中定义一个entry,该entry指明了需要使用的创建Content URI的Authority。此外,还需要一个XML文件的文件名,该XML文件指定了我们的应用可以共享的目录路径。
<provider android:name="android.support.v4.content.FileProvider" android:authorities="com.package.fileprovider" android:exported="false" android:grantUriPermissions="true"> <meta-data android:name="android.support.FILE_PROVIDER_PATHS" android:resource="@xml/file_paths" /> </provider>
manifest中定义的时候有两点需要注意 :
-
android:authorities 字段指定了希望使用的Authority,该Authority针对于FileProvider所生成的content URI。本例中我的应用的包名为
com.package.fileprovider
对于自己的应用,要在我们的应用程序包名(android:package的值)之后继续追加“fileprovider”来指定Authority。 -
<provider>
下的<meta-data>
指向了一个XML文件,该文件指定了我们希望共享的目录路径。“android:resource”属性字段是这个文件的路径和名字(无“.xml”后缀)
2: 设置合适的路径
一旦在Manifest清单文件中为自己的应用添加了FileProvider,就需要指定我们希望共享文件的目录路径。为指定该路径,首先要在“res/xml/”下创建文件“filepaths.xml”。在这个文件中,为每一个想要共享目录添加一个XML标签。
<?xml version="1.0" encoding="utf-8"?> <paths xmlns:android="http://schemas.android.com/apk/res/android"> <files-path path="libs" name="files"/> </paths>
<files-path name="name" path="path" />
内部存储路径,与Context.getFilesDir()返回的路径一致- name代表URI的路径,为了安全起见,隐藏了具体的目录位置 , 具体的目录位置由path字段指定
- 所有的path指定的都是目录名,包含了旗下的子目录,而不是文件名.无法通过文件名来指定单个文件,也无法通过通配符的形式指定一系列子文件.
客户端请求so库文件
跳转到service端的Activity
Intent intent = new Intent(Intent.ACTION_MAIN);
//参数是包名,类全限定名,注意直接用类名不行
ComponentName cn = new ComponentName("com.package", "com.package.ServiceActivity");
intent.setComponent(cn);
startActivityForResult(intent, 5);
服务端分享so库文件
File file = new File(getFilesDir() + "libs/", "xxx.so"); Uri uriForFile = getUriForFile(this, file); Intent intent = new Intent(); intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION | Intent.FLAG_GRANT_WRITE_URI_PERMISSION); intent.setDataAndType(uriForFile, getContentResolver().getType(uriForFile)); intent.setData(uriForFile); setResult(2, intent); finish(); public static Uri getUriForFile(Context context, File file) { Uri fileUri = null; if (Build.VERSION.SDK_INT >= 24) { fileUri = getUriForFile24(context, file); } else { fileUri = Uri.fromFile(file); } return fileUri; } public static Uri getUriForFile24(Context context, File file) { Uri fileUri = android.support.v4.content.FileProvider.getUriForFile(context, context.getPackageName() + ".fileprovider", file); return fileUri; }
客户端处理服务端分享的so库文件
@Override protected void onActivityResult(int requestCode, int resultCode, @Nullable Intent data) { super.onActivityResult(requestCode, resultCode, data); if (resultCode == 2) { Uri serviceUri = data.getData(); Log.d(TAG, getFilePathForN(serviceUri, this)); String filePathForN = getFilePathForN(serviceUri, this); System.load(filePathForN); } } private static String getFilePathForN(Uri uri, Context context) { Uri returnUri = uri; Cursor returnCursor = context.getContentResolver().query(returnUri, null, null, null, null); /* * Get the column indexes of the data in the Cursor, * * move to the first row in the Cursor, get the data, * * and display it. * */ int nameIndex = returnCursor.getColumnIndex(OpenableColumns.DISPLAY_NAME); int sizeIndex = returnCursor.getColumnIndex(OpenableColumns.SIZE); returnCursor.moveToFirst(); String name = (returnCursor.getString(nameIndex)); String size = (Long.toString(returnCursor.getLong(sizeIndex))); File file = new File(context.getFilesDir(), name); try { InputStream inputStream = context.getContentResolver().openInputStream(uri); FileOutputStream outputStream = new FileOutputStream(file); int read = 0; int maxBufferSize = 1 * 1024 * 1024; int bytesAvailable = inputStream.available(); //int bufferSize = 1024; int bufferSize = Math.min(bytesAvailable, maxBufferSize); final byte[] buffers = new byte[bufferSize]; while ((read = inputStream.read(buffers)) != -1) { outputStream.write(buffers, 0, read); } Log.e("File Size", "Size " + file.length()); Log.e("File Size", "name " + name); inputStream.close(); outputStream.close(); Log.e("File Path", "Path " + file.getPath()); Log.e("File Size", "Size " + file.length()); } catch (Exception e) { Log.e("Exception", e.getMessage()); } return file.getPath(); }
到此分享完成,客户端加载完成。