我想以编程方式截取屏幕截图并使用 ShareActionProvider 分享,而不要求" android.permission.WRITE_EXTERNAL_STORAGE "允许。 我试图这样做是因为我想避免要求权限,如果它不是绝对必要的,并且能够在没有外部存储的情况下处理设备。
我设法成功将屏幕截图发送到某些应用,但至少有一个(Gmail)无法附加我的屏幕截图。 这是我的代码:
...
@Override
public void onCreateOptionsMenu(Menu menu, MenuInflater inflater) {
...
MenuItem shareMenuItem = menu.findItem(R.id.action_share);
ShareActionProvider shareActionProvider = (ShareActionProvider) MenuItemCompat.getActionProvider(shareMenuItem);
shareActionProvider.setShareIntent(createShareIntent());
shareActionProvider.setOnShareTargetSelectedListener(new ShareActionProvider.OnShareTargetSelectedListener()
{
@Override
public boolean onShareTargetSelected(ShareActionProvider source, Intent intent)
{
saveScreenshot();
// The return result is ignored. Return false for consistency.
return false;
}
});
}
private Intent createShareIntent() {
// Get the path of the screenshot inside the directory holding application files.
File screenshotFile = new File(getActivity().getApplicationContext().getFilesDir(), SCREENSHOT_NAME);
Intent shareIntent = new Intent(Intent.ACTION_SEND);
shareIntent.setType("image/jpeg");
shareIntent.putExtra(Intent.EXTRA_STREAM, Uri.fromFile(screenshotFile));
return shareIntent;
}
private void saveScreenshot() {
view.setDrawingCacheEnabled(true);
Bitmap bitmap = Bitmap.createBitmap(view.getDrawingCache());
view.setDrawingCacheEnabled(false);
// Save on Internal Storage to avoid asking for WRITE_EXTERNAL_STORAGE permission.
FileOutputStream outputStream = null;
try {
// Open a file associated with this Context's application package for writing.
// Make file readable by other apps otherwise it can't be shared.
outputStream = getActivity().getApplicationContext()
.openFileOutput(SCREENSHOT_NAME, Context.MODE_WORLD_READABLE);
bitmap.compress(Bitmap.CompressFormat.JPEG, COMPRESS_QUALITY, outputStream);
outputStream.close();
} catch (IOException e) {
Log.e(LOG_TAG, "Can't save screenshot!", e);
} finally {
if (outputStream != null) {
try {
outputStream.close();
} catch (IOException e) {
Log.e(LOG_TAG, "Can't close the output stream!", e);
}
}
}
}
...
如果我想与Google和其他我测试过的应用分享Twitter,环聊,Keep,Evernote,Inbox,这个代码有效,但它不适用于Gmail。 例如,在Nexus 6上,Gmail向我发送了一条Toast消息,说明" 权限被拒绝"并且在Nexus 4上它没有附加屏幕截图而没有任何错误消息。 日志中没有任何相关内容。 使用像
这样的东西screenshotFile.setReadable(true, false);
或
try {
Runtime.getRuntime().exec("chmod 777 " + screenshotFile.getAbsolutePath());
} catch (IOException e) {
Log.e(LOG_TAG, "Can't give permissions to screenshot file!", e);
}
没有什么区别。
如果我使用 Environment.getExternalStorageDirectory()将屏幕截图保存在外部存储上,并要求输入" android.permission.WRITE_EXTERNAL_STORAGE "允许我测试的所有应用程序工作正常。
如何在不使用外部存储的情况下执行此操作并让所有应用(包括Gmail)都能正常运行? 这可能是Gmail应用程序的问题吗? 或者你会建议我只是要求允许在外部存储上写,并接受我的一些用户可能会抱怨并且某些设备没有SD卡的事实?
谢谢!
答案 0 :(得分:2)
这是使用fileprovider实现所需功能所必须做的。我在我的应用程序中完成了它。
将文件创建为 res / xml / paths.xml 并添加此
@Configuration
public class ZuulConfiguration {
@Bean
protected OAuth2RestTemplate oauth2RestTemplate(OAuth2ProtectedResourceDetails resource,
OAuth2ClientContext context) {
return new OAuth2RestTemplate(resource, context);
}
}
然后使用您的包名称 AndroidManifest.xml android替换 android:authorities属性中的fileprovider
<?xml version="1.0" encoding="utf-8"?>
<paths >
<cache-path name="shared_images" path="images/"/>
</paths>
然后使用此方法分享您的位图
<provider
android:name="android.support.v4.content.FileProvider"
android:authorities="com.harkunwar.testapp.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/filepaths" />
</provider>
然后我使用这个简单的代码使用上一个函数共享截图。
void share(Bitmap bitmap) {
String fileName = "share.png";
File dir = new File(getCacheDir(), "images");
dir.mkdirs();
File file = new File(dir, fileName);
try {
FileOutputStream fOut = new FileOutputStream(file);
bitmap.compress(Bitmap.CompressFormat.PNG, 100, fOut);
fOut.flush();
fOut.close();
} catch (Exception e) {
e.printStackTrace();
}
Uri uri = FileProvider.getUriForFile(this, getPackageName()+".fileprovider", file);
Intent intent = new Intent();
intent.setAction(Intent.ACTION_SEND);
intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION);
intent.setType("image/*");
intent.setDataAndType(uri, getContentResolver().getType(uri));
intent.putExtra(Intent.EXTRA_SUBJECT, "");
intent.putExtra(Intent.EXTRA_TEXT, "Here's the shared image");
intent.putExtra(Intent.EXTRA_STREAM, uri);
try {
startActivity(Intent.createChooser(intent, "Share Image"));
} catch (ActivityNotFoundException e) {
Toast.makeText(this, "No App Available", Toast.LENGTH_SHORT).show();
}
}
答案 1 :(得分:0)
如何在不使用外部存储设备的情况下执行此操作并让所有应用程序(包括Gmail)都能正常运行?
您可以try FileProvider
,可能与my LegacyCompatCursorWrapper
一起使用。
这可能是Gmail应用的问题吗?
我认为它是一个功能,而不是一个bug。 MODE_WORLD_READABLE
已被弃用了一段时间,原因很充分。就目前而言,您的代码正在使您的屏幕截图可供所有应用程序使用,从安全角度来看这很差。正确使用ContentProvider
可以限制对一个请求(不是所有)的访问,对于一个请求(此特定ACTION_SEND
操作),在有限的时间内。也许Gmail开发人员只是试图让其他人朝着正确的方向努力。
某些设备没有SD卡?
External storage在大多数Android设备上都不是removable storage,包括Android 3.0或更高版本附带的所有设备。如果您发现设备型号附带更新的设备型号,外部存储设备是可移动卡,请告知我们。