6

https://developer.android.com/training/secure-file-sharing/index.htmlに従い、アプリの内部ディレクトリ (/data/data/package/files/xxx/) 内のファイルをクライアント アプリに共有することができます。ファイルプロバイダー。

(内部ディレクトリではなく) assets フォルダー内のファイルをクライアント アプリに共有する方法。

ありがとう

4

2 に答える 2

3

CommonsWare の CWAC-Providerを参照してください。これは、必要なことを正確に実行するためのライブラリです。

于 2015-07-22T08:48:32.597 に答える
2

これが私が最終的に使用した方法です。これが誰かの助けになることを願っています。マニフェスト ファイルにプロバイダーを追加

        <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 Activity 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;
}
}

アセット ファイルの圧縮を回避する Gradle ビルド オプション (これらは、アセットに含まれていたファイルの種類です)

aaptOptions {
    noCompress '.json' , '.xls'
}

Consumer アクティビティのフォロー

onCreate() では、ACTION_PICK を特定のアプリケーションに送信するため、setPackage() が必要です。

        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;
                }
            }
        } 
    }
}

AssetFileDescriptor を使用してファイルをコピーする CopyRaw メソッド

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" />
于 2015-07-23T11:26:54.553 に答える