遵循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