遵循https://developer.android.com/training/secure-file-sharing/index.html并能够使用fileprovider将应用程序的内部目录(/ data/data/package/files/xxx /)中的文件共享到客户端应用程序。使用fileprovider共享资源
如何将资产文件夹中的文件(而不是内部目录)共享到客户端应用程序。
感谢
遵循https://developer.android.com/training/secure-file-sharing/index.html并能够使用fileprovider将应用程序的内部目录(/ data/data/package/files/xxx /)中的文件共享到客户端应用程序。使用fileprovider共享资源
如何将资产文件夹中的文件(而不是内部目录)共享到客户端应用程序。
感谢
请参阅从CommonsWare CWAC-Provider这是做正是你想要的库。
这是我最后使用的方式,希望这会帮助别人。 新增供应商清单文件
<provider
android:name=".AssetsProvider"
android:authorities="yourpackage.provider"
android:exported="true"
android:grantUriPermissions="true"
android:readPermission="yourpermission"></provider>
<activity
android:name=".MainActivity"
android:label="@string/app_name"
android:screenOrientation="landscape">
<intent-filter>
<action android:name="android.intent.action.PICK" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.OPENABLE" />
<data android:mimeType="application/octet-stream" />
</intent-filter>
</activity>
继inProvider活动的onCreate(),以获得资产列表并返回uriArray给调用者(消费者应用程序)
String[] assetFilesList = null;
// Get Asset Mangaer
AssetManager assetManager = getAssets();
try {
assetFilesList = assetManager.list();
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
// Set up an Intent to send back to apps that request files
mResultIntent = new Intent("yourpackage.ACTION_SEND_MULTIPLE");
// new Uri list
ArrayList<Uri> uriArrayList = new ArrayList<>();
// Set the Activity's result to null to begin with
setResult(Activity.RESULT_CANCELED, null);
Uri fileUri;
if (assetFilesList != null) {
for (String currFile : assetFilesList) {
Log.i(TAG, "Adding File " + currFile);
// parse and create uri
fileUri = Uri.parse("content://" + this.getPackageName() + ".provider/" + currFile);
// add current file uri to the list
uriArrayList.add(fileUri);
}
}
else {
Log.e(TAG, "files array is pointing to null");
}
if (uriArrayList.size() != 0) {
// Put the UriList Intent
mResultIntent.putParcelableArrayListExtra(Intent.EXTRA_STREAM, uriArrayList);
mResultIntent.setType("application/octet-stream");
// Set the result
this.setResult(Activity.RESULT_OK, mResultIntent);
} else {
// Set the result to failed
mResultIntent.setDataAndType(null, "");
this.setResult(RESULT_CANCELED, mResultIntent);
}
// Finish Activity and return Result to Caller
finish();
我的资产提供者类,我还没有实现查询,更新等...因为这些不是我的情况所必需的。
public class AssetsProvider extends ContentProvider {
static final String TAG = "AssetsProvider";
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
Log.v(TAG, "AssetsGetter: Open asset file " + uri.toString());
AssetManager am = getContext().getAssets();
String file_name = uri.getLastPathSegment();
if (file_name == null)
throw new FileNotFoundException();
AssetFileDescriptor afd = null;
try {
afd = am.openFd(file_name);
} catch (IOException e) {
Log.e(TAG, Log.getStackTraceString(e));
}
return afd;
}
@Override
public String getType(Uri p1) {
// TODO: Implement this method
return null;
}
@Override
public int delete(Uri p1, String p2, String[] p3) {
// TODO: Implement this method
return 0;
}
@Override
public Cursor query(Uri p1, String[] p2, String p3, String[] p4, String p5) {
// TODO: Implement this method
return null;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder, CancellationSignal cancellationSignal) {
// TODO: Implement this method
return super.query(uri, projection, selection, selectionArgs, sortOrder, cancellationSignal);
}
@Override
public Uri insert(Uri p1, ContentValues p2) {
// TODO: Implement this method
return null;
}
@Override
public boolean onCreate() {
// TODO: Implement this method
return false;
}
@Override
public int update(Uri p1, ContentValues p2, String p3, String[] p4) {
// TODO: Implement this method
return 0;
}
}
摇篮构建选项,以避免资产的文件压缩(这是文件的类型,我在资产)
aaptOptions {
noCompress '.json' , '.xls'
}
继在消费活动
在的onCreate() - setPackage()是必需的,因为我们要将ACTION_PICK发送到特定应用程序
Intent mRequestFileIntent = new Intent(Intent.ACTION_PICK);
mRequestFileIntent.setPackage("yourAssetsProviderpackage");
mRequestFileIntent.setType("application/octet-stream");
try {
startActivityForResult(mRequestFileIntent, 0);
} catch (Exception e) {
e.printStackTrace();
Toast.makeText(this, "Install Assets Provider app before start", Toast.LENGTH_LONG).show();
finish();
}
新增覆盖方法onActivityResult()
public void onActivityResult(int requestCode, int resultCode,
Intent returnIntent) {
// If the selection didn't work
if (resultCode != Activity.RESULT_OK) {
// Exit without doing anything else
Log.e(TAG, "Activity returned fail");
} else {
// get array list
ArrayList<Uri> uriArrayList = returnIntent.getParcelableArrayListExtra(Intent.EXTRA_STREAM);
// create directory in internal storage to store the assets from uri list
String toPath = this.getFilesDir().getPath();
if (uriArrayList != null) {
AssetFileDescriptor mInputAFD;
for (int i = 0; i < uriArrayList.size(); i++) {
// Get the file's content URI
Uri returnUri = uriArrayList.get(i);
try {
mInputAFD = getContentResolver().openAssetFileDescriptor(returnUri, "r");
// Get file name
String fileName = returnUri.getLastPathSegment();
Log.i(TAG, "URI " + returnUri.toString() + " fileName " + fileName);
// Create dest filename and copy
File dest = new File(toPath + "/" + fileName);
copyRaw(mInputAFD, dest);
} catch (Exception e) {
Log.e(TAG, Log.getStackTraceString(e));
// Break loop at first exception
break;
}
}
}
}
}
CopyRaw方法使用AssetFileDescriptor
public void copyRaw(AssetFileDescriptor fd, File destinationFile) throws IOException {
FileChannel sourceChannel = new FileInputStream(fd.getFileDescriptor()).getChannel();
FileChannel destinationChannel = new FileOutputStream(destinationFile).getChannel();
sourceChannel.transferTo(fd.getStartOffset(), fd.getLength(), destinationChannel);
}
添加权限消费清单文件
<uses-permission android:name="yourpermission" />
由于复制的文件,这有助于 – user207064