Kir*_*irk 41 android android-contentprovider android-file
我的目标是在内部存储上创建XML文件,然后通过共享Intent发送它.
我可以使用此代码创建XML文件
FileOutputStream outputStream = context.openFileOutput(fileName, Context.MODE_WORLD_READABLE);
PrintStream printStream = new PrintStream(outputStream);
String xml = this.writeXml(); // get XML here
printStream.println(xml);
printStream.close();
Run Code Online (Sandbox Code Playgroud)
我试图将Uri检索到输出文件以便共享它.我首先尝试通过将文件转换为Uri来访问该文件
File outFile = context.getFileStreamPath(fileName);
return Uri.fromFile(outFile);
Run Code Online (Sandbox Code Playgroud)
这将返回file:///data/data/com.my.package/files/myfile.xml但我似乎无法将其附加到电子邮件,上传等.
如果我手动检查文件长度,它是正确的,并显示有一个合理的文件大小.
接下来,我创建了一个内容提供程序并尝试引用该文件,它不是该文件的有效句柄.在ContentProvider没有以往任何时候都似乎被称为任意点.
Uri uri = Uri.parse("content://" + CachedFileProvider.AUTHORITY + "/" + fileName);
return uri;
Run Code Online (Sandbox Code Playgroud)
这将返回内容://com.my.package.provider/myfile.xml但我检查文件并且它的长度为零.
如何正确访问文件?我是否需要使用内容提供商创建文件?如果是这样,怎么样?
更新
这是我用来分享的代码.如果我选择Gmail,它会显示为附件,但是当我发送它时会出现错误无法显示附件,并且到达的电子邮件没有附件.
public void onClick(View view) {
Log.d(TAG, "onClick " + view.getId());
switch (view.getId()) {
case R.id.share_cancel:
setResult(RESULT_CANCELED, getIntent());
finish();
break;
case R.id.share_share:
MyXml xml = new MyXml();
Uri uri;
try {
uri = xml.writeXmlToFile(getApplicationContext(), "myfile.xml");
//uri is "file:///data/data/com.my.package/files/myfile.xml"
Log.d(TAG, "Share URI: " + uri.toString() + " path: " + uri.getPath());
File f = new File(uri.getPath());
Log.d(TAG, "File length: " + f.length());
// shows a valid file size
Intent shareIntent = new Intent();
shareIntent.setAction(Intent.ACTION_SEND);
shareIntent.putExtra(Intent.EXTRA_STREAM, uri);
shareIntent.setType("text/plain");
startActivity(Intent.createChooser(shareIntent, "Share"));
} catch (FileNotFoundException e) {
e.printStackTrace();
}
break;
}
}
Run Code Online (Sandbox Code Playgroud)
我注意到Exception这里有一个从createChooser(...)里面抛出的东西,但我无法弄清楚为什么抛出它.
E/ActivityThread(572):活动com.android.internal.app.ChooserActivity已泄漏,最初这里注册IntentReceiver com.android.internal.app.ResolverActivity$1@4148d658.你是否错过了对unregisterReceiver()的调用?
我研究了这个错误,找不到任何明显的东西.这两个链接都表明我需要取消注册接收器.
我有一个接收器设置,但它AlarmManager是在其他地方设置的,并不需要应用程序注册/取消注册.
openFile代码(...)
如果需要,这里是我创建的内容提供商.
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
String fileLocation = getContext().getCacheDir() + "/" + uri.getLastPathSegment();
ParcelFileDescriptor pfd = ParcelFileDescriptor.open(new File(fileLocation), ParcelFileDescriptor.MODE_READ_ONLY);
return pfd;
}
Run Code Online (Sandbox Code Playgroud)
Rob*_*Rob 38
可以通过ContentProvider公开存储在应用程序专用目录中的文件.下面是一些示例代码,展示了如何创建可以执行此操作的内容提供程序.
表现
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.example.providertest"
android:versionCode="1"
android:versionName="1.0">
<uses-sdk android:minSdkVersion="11" android:targetSdkVersion="15" />
<application android:label="@string/app_name"
android:icon="@drawable/ic_launcher"
android:theme="@style/AppTheme">
<activity
android:name=".MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<provider
android:name="MyProvider"
android:authorities="com.example.prov"
android:exported="true"
/>
</application>
</manifest>
Run Code Online (Sandbox Code Playgroud)
在您的ContentProvider中重写openFile以返回ParcelFileDescriptor
@Override
public ParcelFileDescriptor openFile(Uri uri, String mode) throws FileNotFoundException {
File cacheDir = getContext().getCacheDir();
File privateFile = new File(cacheDir, "file.xml");
return ParcelFileDescriptor.open(privateFile, ParcelFileDescriptor.MODE_READ_ONLY);
}
Run Code Online (Sandbox Code Playgroud)
确保已将xml文件复制到缓存目录
private void copyFileToInternal() {
try {
InputStream is = getAssets().open("file.xml");
File cacheDir = getCacheDir();
File outFile = new File(cacheDir, "file.xml");
OutputStream os = new FileOutputStream(outFile.getAbsolutePath());
byte[] buff = new byte[1024];
int len;
while ((len = is.read(buff)) > 0) {
os.write(buff, 0, len);
}
os.flush();
os.close();
is.close();
} catch (IOException e) {
e.printStackTrace(); // TODO: should close streams properly here
}
}
Run Code Online (Sandbox Code Playgroud)
现在任何其他应用程序都应该能够通过使用内容uri获取私有文件的InputStream(内容://com.example.prov/myfile.xml)
对于简单的测试,请从类似于以下内容的单独应用程序中调用内容提供程序
private class MyTask extends AsyncTask<String, Integer, String> {
@Override
protected String doInBackground(String... params) {
Uri uri = Uri.parse("content://com.example.prov/myfile.xml");
InputStream is = null;
StringBuilder result = new StringBuilder();
try {
is = getApplicationContext().getContentResolver().openInputStream(uri);
BufferedReader r = new BufferedReader(new InputStreamReader(is));
String line;
while ((line = r.readLine()) != null) {
result.append(line);
}
} catch (FileNotFoundException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
} finally {
try { if (is != null) is.close(); } catch (IOException e) { }
}
return result.toString();
}
@Override
protected void onPostExecute(String result) {
Toast.makeText(CallerActivity.this, result, Toast.LENGTH_LONG).show();
super.onPostExecute(result);
}
}
Run Code Online (Sandbox Code Playgroud)
Dus*_*sko 15
所以罗布的回答是正确的我假设但是我的做法有点不同.据我所知,通过提供者中的设置:
android:exported="true"
Run Code Online (Sandbox Code Playgroud)
您是否可以公开访问所有文件?!无论如何,只允许访问某些文件的方法是以下列方式定义文件路径权限:
<provider
android:authorities="com.your.app.package"
android:name="android.support.v4.content.FileProvider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/file_paths" />
</provider>
Run Code Online (Sandbox Code Playgroud)
然后在XML目录中定义file_paths.xml文件,如下所示:
<paths xmlns:android="http://schemas.android.com/apk/res/android">
<files-path path="/" name="allfiles" />
<files-path path="tmp/" name="tmp" />
</paths>
Run Code Online (Sandbox Code Playgroud)
现在,"allfiles"提供了相同类型的公共权限,我猜是选项android:exported ="true",但你真的不想我想这样定义一个子目录就是下一行.然后你所要做的就是存储你想要分享的文件,在那个目录中.
接下来你要做的就是,Rob也说,获取这个文件的URI.我就这样做了:
Uri contentUri = FileProvider.getUriForFile(context, "com.your.app.package", sharedFile);
Run Code Online (Sandbox Code Playgroud)
然后,当我有这个URI时,我必须附加其他应用程序使用它的权限.我正在使用或发送此文件URI到相机应用程序.无论如何,这是我获得其他应用程序包信息并授予URI权限的方式:
PackageManager packageManager = getPackageManager();
List<ResolveInfo> list = packageManager.queryIntentActivities(cameraIntent, PackageManager.MATCH_DEFAULT_ONLY);
if (list.size() < 1) {
return;
}
String packageName = list.get(0).activityInfo.packageName;
grantUriPermission(packageName, sharedFileUri, Intent.FLAG_GRANT_WRITE_URI_PERMISSION | Intent.FLAG_GRANT_READ_URI_PERMISSION);
ClipData clipData = ClipData.newRawUri("CAMFILE", sharedFileUri);
cameraIntent.setClipData(clipData);
cameraIntent.setFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION);
cameraIntent.setFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
startActivityForResult(cameraIntent, GET_FROM_CAMERA);
Run Code Online (Sandbox Code Playgroud)
我留下了相机的代码,因为我不想采取其他一些我没有工作的例子.但是这样你就可以看到你可以为URI本身附加权限了.
相机的事情是我可以通过ClipData设置它,然后另外设置权限.我想在您的情况下,您只需要FLAG_GRANT_READ_URI_PERMISSION,因为您要将文件附加到电子邮件中.
这是我在FileProvider上提供帮助的链接,因为我根据我在那里找到的信息发布了所有帖子.虽然找到相机应用程序的包信息有些麻烦.
希望能帮助到你.
上述答案都没有帮助。我的问题是传递意图附加内容,但我将引导您完成共享文件的所有步骤。
第 1 步:创建内容提供程序 这将使您想要共享的任何应用程序都可以访问该文件。将以下内容粘贴到 Manifest.xml 文件中的<application></applicatio>标签内
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="{YOUR_PACKAGE_NAME}.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/provider_paths" />
</provider>
Run Code Online (Sandbox Code Playgroud)
步骤 2:定义内容提供者可访问的路径 通过在 res/xml 下创建一个名为provider_paths.xml(或您选择的名称)的文件来执行此操作。将以下代码放入文件中
<?xml version="1.0" encoding="utf-8"?>
<paths>
<external-path
name="external"
path="." />
<external-files-path
name="external_files"
path="." />
<cache-path
name="cache"
path="." />
<external-cache-path
name="external_cache"
path="." />
<files-path
name="files"
path="." />
</paths>
Run Code Online (Sandbox Code Playgroud)
步骤 3:创建共享文件的 Intent
Intent intentShareFile = new Intent(Intent.ACTION_SEND);
Uri uri = FileProvider.getUriForFile(getApplicationContext(), getPackageName() + ".fileprovider", fileToShare);
intentShareFile.setDataAndType(uri, URLConnection.guessContentTypeFromName(fileToShare.getName()));
//Allow sharing apps to read the file Uri
intentShareFile.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
//Pass the file Uri instead of the path
intentShareFile.putExtra(Intent.EXTRA_STREAM,
uri);
startActivity(Intent.createChooser(intentShareFile, "Share File"));
Run Code Online (Sandbox Code Playgroud)
| 归档时间: |
|
| 查看次数: |
39107 次 |
| 最近记录: |