web-dev-qa-db-ja.com

androidアセットフォルダーから画像を共有する

アセットフォルダの画像を共有しようとしています。私のコードは:

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"));

しかし、それは機能しません。あなたはなにか考えはありますか?

20
Buda Gavril

何を補完する @ 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

11
Kikuto

カスタムContentProviderを介してアセットフォルダからファイル(画像を含む)を共有することが可能です

ContentProviderを拡張し、マニフェストに登録して、openAssetFileメソッドを実装する必要があります。その後、Urisを介して資産を評価できます

    @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;
    }
15
smith324

このブログはそれをすべて説明しています:
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);
11
intrepidis

多くのアプリでは、画像の名前とサイズを指定する必要があります。したがって、ここに改善されたコードがあります(例として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;
    }
}
3

ちなみに、assetsフォルダの画像を共有する方法はありません。ただし、resフォルダーからリソースを共有することは可能です。

2
Michael

アセットフォルダーから共有するには、 cwac-provider ライブラリ(StreamProvider)のみをお勧めします。

独自のコンテンツプロバイダーの開発を回避する中で、気まぐれなレガシーアプリのサポートを追加します(チェックUSE_LEGACY_CURSOR_WRAPPER)。

2

ここにある他の回答はどれも私には役に立たなかったので(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 ...」アクションに使用することもできます。 assetsfilesDir、...の場合、もちろんActivityにいるか、Contextを持っている必要があります。

0