アセットフォルダの画像を共有しようとしています。私のコードは:
Intent share = new Intent(Intent.ACTION_SEND);
share.setType("image/jpg");
share.putExtra(Intent.EXTRA_STREAM, Uri.parse("file:///assets/myImage.jpg"));
startActivity(Intent.createChooser(share, "Share This Image"));
しかし、それは機能しません。あなたはなにか考えはありますか?
何を補完する @ intrepidis 答えた:
上記のサンプルクラスのようなオーバーライドメソッドが必要になります。
package com.Android.example;
import Android.content.ContentProvider;
import Android.net.Uri;
import Android.content.res.AssetFileDescriptor;
import Android.content.res.AssetManager;
import Java.io.FileNotFoundException;
import Android.content.ContentValues;
import Android.database.Cursor;
import Java.io.IOException;
import Android.os.CancellationSignal;
public class AssetsProvider extends ContentProvider
{
@Override
public AssetFileDescriptor openAssetFile( Uri uri, String mode ) throws FileNotFoundException
{
Log.v( TAG, "AssetsGetter: Open asset file" );
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)
{
e.printStackTrace( );
}
return afd;//super.openAssetFile(uri, mode);
}
@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;
}
}
クエリメソッドを2回オーバーライドする必要がありました。そして、androidmanifest.xmlのタグの上に次の行を追加します。
<provider
Android:name="com.Android.example.AssetsProvider"
Android:authorities="com.Android.example"
Android:grantUriPermissions="true"
Android:exported="true" />
そしてこれで、すべてが魅力のように機能します:D
カスタムContentProvider
を介してアセットフォルダからファイル(画像を含む)を共有することが可能です
ContentProvider
を拡張し、マニフェストに登録して、openAssetFile
メソッドを実装する必要があります。その後、Uri
sを介して資産を評価できます
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
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) {
e.printStackTrace();
}
return afd;
}
このブログはそれをすべて説明しています:
http://nowherenearithaca.blogspot.co.uk/2012/03/too-easy-using-contentprovider-to-send.html
基本的に、これはマニフェストに含まれます。
<provider Android:name="yourclass.that.extendsContentProvider" Android:authorities="com.yourdomain.whatever"/>
コンテンツプロバイダークラスには次のものがあります。
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
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) {
e.printStackTrace();
}
return afd;//super.openAssetFile(uri, mode);
}
そして、呼び出しコードはこれを行います:
Uri theUri = Uri.parse("content://com.yourdomain.whatever/someFileInAssetsFolder");
Intent theIntent = new Intent(Intent.ACTION_SEND);
theIntent.setType("image/*");
theIntent.putExtra(Intent.EXTRA_STREAM,theUri);
theIntent.putExtra(Android.content.Intent.EXTRA_SUBJECT,"Subject for message");
theIntent.putExtra(Android.content.Intent.EXTRA_TEXT, "Body for message");
startActivity(theIntent);
多くのアプリでは、画像の名前とサイズを指定する必要があります。したがって、ここに改善されたコードがあります(例としてGoogleのFileProviderコードを使用):
public class AssetsProvider extends ContentProvider {
private final static String LOG_TAG = AssetsProvider.class.getName();
private static final String[] COLUMNS = {
OpenableColumns.DISPLAY_NAME, OpenableColumns.SIZE };
@Override
public boolean onCreate() {
return true;
}
@Override
public Cursor query(Uri uri, String[] projection, String selection, String[] selectionArgs, String sortOrder) {
/**
* Source: {@link FileProvider#query(Uri, String[], String, String[], String)} .
*/
if (projection == null) {
projection = COLUMNS;
}
final AssetManager am = getContext().getAssets();
final String path = getRelativePath(uri);
long fileSize = 0;
try {
final AssetFileDescriptor afd = am.openFd(path);
fileSize = afd.getLength();
afd.close();
} catch(IOException e) {
Log.e(LOG_TAG, "Can't open asset file", e);
}
final String[] cols = new String[projection.length];
final Object[] values = new Object[projection.length];
int i = 0;
for (String col : projection) {
if (OpenableColumns.DISPLAY_NAME.equals(col)) {
cols[i] = OpenableColumns.DISPLAY_NAME;
values[i++] = uri.getLastPathSegment();
} else if (OpenableColumns.SIZE.equals(col)) {
cols[i] = OpenableColumns.SIZE;
values[i++] = fileSize;
}
}
final MatrixCursor cursor = new MatrixCursor(cols, 1);
cursor.addRow(values);
return cursor;
}
@Override
public String getType(Uri uri) {
/**
* Source: {@link FileProvider#getType(Uri)} .
*/
final String file_name = uri.getLastPathSegment();
final int lastDot = file_name.lastIndexOf('.');
if (lastDot >= 0) {
final String extension = file_name.substring(lastDot + 1);
final String mime = MimeTypeMap.getSingleton().getMimeTypeFromExtension(extension);
if (mime != null) {
return mime;
}
}
return "application/octet-stream";
}
@Override
public Uri insert(Uri uri, ContentValues values) {
return null;
}
@Override
public int delete(Uri uri, String selection, String[] selectionArgs) {
return 0;
}
@Override
public int update(Uri uri, ContentValues values, String selection, String[] selectionArgs) {
return 0;
}
@Override
public AssetFileDescriptor openAssetFile(Uri uri, String mode) throws FileNotFoundException {
final AssetManager am = getContext().getAssets();
final String path = getRelativePath(uri);
if(path == null) {
throw new FileNotFoundException();
}
AssetFileDescriptor afd = null;
try {
afd = am.openFd(path);
} catch(IOException e) {
Log.e(LOG_TAG, "Can't open asset file", e);
}
return afd;
}
private String getRelativePath(Uri uri) {
String path = uri.getPath();
if (path.charAt(0) == '/') {
path = path.substring(1);
}
return path;
}
}
ちなみに、assets
フォルダの画像を共有する方法はありません。ただし、res
フォルダーからリソースを共有することは可能です。
アセットフォルダーから共有するには、 cwac-provider ライブラリ(StreamProvider)のみをお勧めします。
独自のコンテンツプロバイダーの開発を回避する中で、気まぐれなレガシーアプリのサポートを追加します(チェックUSE_LEGACY_CURSOR_WRAPPER
)。
ここにある他の回答はどれも私には役に立たなかったので(2019年)、アセットをアプリの内部ファイルディレクトリにコピーしてから、このファイルを共有することで回避策を作成しました。私の場合、アセットフォルダーからPDFファイルを共有する必要がありました。
AndroidManifest.xmlで、ファイルプロバイダーを追加します(カスタムプロバイダーを使用する必要はありません)。
_<provider
Android:name="androidx.core.content.FileProvider"
Android:authorities="${applicationId}.provider"
Android:exported="false"
Android:grantUriPermissions="true">
<meta-data
Android:name="Android.support.FILE_PROVIDER_PATHS"
Android:resource="@xml/filepaths" />
</provider>
_
Res/xml /にfilepaths.xmlファイルを作成します
_<?xml version="1.0" encoding="utf-8"?>
<paths>
<files-path
name="root"
path="/" />
</paths>
_
もちろん、アプリディレクトリ内の他のファイルを管理する場合は、ここでサブディレクトリを使用する必要があります。
これで、共有インテントをトリガーするクラスになりました。
1。ファイルディレクトリに空のファイルを作成します
_private fun createFileInFilesDir(filename: String): File {
val file = File(filesDir.path + "/" + filename)
if (file.exists()) {
if (!file.delete()) {
throw IOException()
}
}
if (!file.createNewFile()) {
throw IOException()
}
return file
}
_
2。アセットのコンテンツをファイルにコピーします
_private fun copyAssetToFile(assetName: String, file: File) {
val buffer = ByteArray(1024)
val inputStream = assets.open(assetName)
val outputStream: OutputStream = FileOutputStream(file)
while (inputStream.read(buffer) > 0) {
outputStream.write(buffer)
}
}
_
。ファイルの共有インテントを作成します
_private fun createIntentForFile(file: File, intentAction: String): Intent {
val uri = FileProvider.getUriForFile(this, applicationContext.packageName + ".provider", file)
val intent = Intent(intentAction)
intent.flags = Intent.FLAG_GRANT_READ_URI_PERMISSION
intent.setDataAndType(uri, "application/pdf")
return intent
}
_
4。1-3を実行し、インテントを実行します
_private fun sharePdfAsset(assetName: String, intentAction: String) {
try {
val file = createFileInFilesDir(assetName)
copyAssetToFile(assetName, file)
val intent = createIntentForFile(file, intentAction)
startActivity(Intent.createChooser(intent, null))
} catch (e: IOException) {
e.printStackTrace()
AlertDialog.Builder(this)
.setTitle(R.string.error)
.setMessage(R.string.share_error)
.show()
}
}
_
5。関数を呼び出す
_sharePdfAsset("your_pdf_asset.pdf", Intent.ACTION_SEND)
_
共有後にファイルを削除したい場合は、おそらくstartActivityForResult()
を使用して後で削除することができます。 intentAction
を変更することにより、_Intent.ACTION_VIEW
_を使用して、このプロセスを「openwith ...」アクションに使用することもできます。 assets
、filesDir
、...の場合、もちろんActivity
にいるか、Context
を持っている必要があります。