当前位置: 首页 > 知识库问答 >
问题:

使用fileprovider共享资产

慕俊语
2023-03-14

跟随https://developer.android.com/training/secure-file-sharing/index.html,并能够共享文件在内部目录(/data/data/pack/files/xxx/)的应用程序到客户端应用程序使用file提供程序。

如何将资产文件夹(而不是内部目录)中的文件共享到客户端应用程序。

谢谢

共有2个答案

许学真
2023-03-14

这是我最后使用的方式,希望这能帮助到某人。在清单文件中添加了提供者

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

Gradle构建选项,以避免压缩资产文件(这些是我在资产中拥有的文件类型)

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

关注消费者活动

在onCreate()中,需要setPackage(),因为我们希望将ACTION\u 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" />
卫俊力
2023-03-14

请参阅来自Common sWare的CWAC-Provider,它是一个库,可以精确地执行您想要的操作。

 类似资料:
  • 但是,执行这一行给了我(为了保护无辜者而改变了名字): 应用程序A在清单文件中有以下内容: filePaths.xml具有: 文件最终的实际路径是: 在这一点上,我被难住了。我不知道为什么不能授予我在同一个应用程序中创建的文件的权限。所以我的问题是:为什么我会得到这个异常,我如何才能成功地授予应用程序B的权限?

  • 我正在尝试使用文件提供商共享存储在我的应用程序内部存储器的原始文件夹中的MP3文件,并允许用户使用他们选择的音频收听应用程序打开共享的MP3文件。 然而,在我编写的代码中,当我尝试使用附加的内容URI作为数据执行意图时,会出现FileNotFoundException。这会导致FileProvider系统的所有其他方面出现故障。 我创建了一个MediaPlayer,让它毫无问题地打开了我想要共享的

  • 资源共享 资源共享目前面临的问题主要包括: 共享过程成本过高; 用户身份评分难 共享服务管理难 短租共享 大量提供短租服务的公司已经开始尝试用区块链来解决共享中的难题。 一份来着 高盛的报告 中宣称: Airbnb 等 P2P 住宿平台已经开始通过利用私人住所打造公开市场来变革住宿行业,但是这种服务的接受程度可能会因人们对人身安全以及财产损失的担忧而受到限制。而如果通过引入安全且无法篡改的数字化资

  • 我正在尝试使用内容提供程序共享我的内部日志文件。我有以下

  • 我看到了很多代码和示例,但我的应用程序还不能正常工作,我想在文件夹,如存储/模拟/0/Android/data/ir。esfandune。mohsen/files/Download/cnt\u imags/images/n1/n1(18)。jpg,我在清单中定义提供者: 和XML: 我的代码是: 但是当发送到其他应用程序时,不要分享任何东西

  • 我正在使用FileProvider API来共享实际存储在内部存储中的内容。 有什么建议我做错了什么吗?