コンテンツ共有用NFC共有ファイル

10420 ワード

Androidでは、Android Beam機能で大きなファイルを転送できますが、NFCとAndroidバージョン(4.1以上のAPI 16)を備えたデバイスでのみ実行できます.さらにAndroid BeamについてはBeaming NDEF Messages to Other Devices、NFCのNear Field Communicationを参照してください.
1.他のデバイスへのファイルの送信
NFCでファイルを送信するには、以下の3つの点が必要です.
  • は権限(NFCとexternal storageの使用権限)を要求する.
  • デバイスがNFCをサポートするかどうかをテストする.
  • Android BeamにURIを提供する.

  • Android Beamファイル転送機能には、次の4つの要件があります.
  • はAndroid 4.1(API 16)以上をサポートする.
  • で転送するファイルはexternal storageにある必要があります.
  • あなたが送信するすべてのファイルはworld-readableでなければなりません.Fileを通じてもいいです.setReadable(true,false)は、この権限を設定する.
  • 転送するファイルに対応するURIを提供する必要があります(FileProvider.getUriForFileで生成されたContent URIは使用できません).

  • 1.1マニフェストで宣言
    1.1.1要求権限
     // NFC
     
     //READ_EXTERNAL_STORAGE
     
    

    注意READ_EXTERNAL_STORAGEという権限は、API 19以前には不要だったが、API 19から必要になったので、ここに加えて、互換性のためである.
    1.1.2 NFC featureの設定
    NFCはhardware featureに属するため、以下のようにラベルを追加する必要があります.
    
    

    注意:
  • android:requiredはtrueであり、デバイスがfeatureを持っていない場合、appが実行できないことを示しています.この機能が選択可能な機能である場合は、android:requiredの値をfalseに設定する必要があります.
  • この属性は告知的なもので、Google Playはこの属性であなたのデバイスがサポートしていないアプリケーションをフィルタします.
  • は、対応する権限を追加することを忘れないように設定する.

  • 1.1.3 SDKバージョンの設定
    Android BeamはAndroid 4.1(API 16)以上しかサポートしていないため、appはこの機能を必要とし、android:minSdkVersion="16"を設定する必要があります.
    1.2デバイスがAndroid Beamに対応しているかどうかをテストする
    デバイスがAndroid Beamをサポートしているかどうかをテストするには、次の3つのステップが必要です.
    i.NFCというfeatrueをoptionalに設定し、以下のようにする.
    
    

    ii. デバイスがNFCをサポートするかどうかをテストする.PackageManagerを呼び出すhasSystemFeature()メソッドおよびFEATURE_NFCがパラメータとして入力.
    // NFC isn't available on the device
    if (!getPackageManager().hasSystemFeature(PackageManager.FEATURE_NFC)) {
        /*
         * Disable NFC features here.
         * For example, disable menu items or buttons that activate
         * NFC-related features
         */
        // Android Beam file transfer isn't supported
    }
    

    iii.デバイスがAndroid Beamをサポートするかどうかをテストする.Androidバージョンを判断することでテストする.
    // Android Beam file transfer isn't supported
    if (Build.VERSION.SDK_INT <
            Build.VERSION_CODES.JELLY_BEAN_MR1) {
        // If Android Beam isn't available, don't continue.
        mAndroidBeamAvailable = false;
        /*
         * Disable Android Beam file transfer features here.
         */
        // Android Beam file transfer is available, continue
    }
    

    デバイスがNFCとAndroid Beamをサポートすることを検証した後、使用時にデバイスがNFCとAndroid Beamの機能をオンにしたかどうかを判断する方法もあり、それぞれa.NfcAdapterのisEnabled()でNFCの機能がオンかどうかを検証することができる.b.NfcAdapterのisNdefPushEnabled()は、Android Beam機能がオンであることを検証する.
    1.3提供ファイルのコールバック方法の作成
    デバイスがAndroid Beamをサポートしてファイル転送を行うことを検証すると、転送したいファイルのレプリカのURIであるUriオブジェクトのセットを返すコールバックメソッドを追加する必要がありますが、Android Beamが他のデバイスにファイルを共有したいと検出すると、システムはコールバックメソッドを呼び出します.このコールバックメソッドを追加するには、NfcAdapterを実装します.CreateBeamUrisCallbackというインタフェースを作成し、overrideの中のcreateBeamUris()という抽象的な方法を以下の例に示します.
    public class MainActivity extends Activity {
        ...
        // List of URIs to provide to Android Beam
        private Uri[] mFileUris = new Uri[10];
        ...
        /**
         * Callback that Android Beam file transfer calls to get
         * files to share
         */
        private class FileUriCallback implements
                NfcAdapter.CreateBeamUrisCallback {
            public FileUriCallback() {
            }
            /**
             * Create content URIs as needed to share with another device
             */
            @Override
            public Uri[] createBeamUris(NfcEvent event) {
                return mFileUris;
            }
        }
        ...
    }
    

    インタフェースが実装されると、このインタフェース実装クラスのインスタンスをAndroid Beamに提供し、setBeamPushUrisCallback()メソッドを使用します.
    public class MainActivity extends Activity {
        ...
        // Instance that returns available files from this app
        private FileUriCallback mFileUriCallback;
        ...
        @Override
        protected void onCreate(Bundle savedInstanceState) {
            ...
            // Android Beam file transfer is available, continue
            ...
            mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
            /*
             * Instantiate a new FileUriCallback to handle requests for
             * URIs
             */
            mFileUriCallback = new FileUriCallback();
            // Set the dynamic callback for URI requests.
            mNfcAdapter.setBeamPushUrisCallback(mFileUriCallback,this);
            ...
        }
        ...
    }
    

    注意:setBeamPushUrisCallback()によってURIを提供するほか、setBeamPushUris()を使用することもできる(方法は、前者は動的であり、後者は固定的である.
    1.4送信するファイルの設定
    /*
     * Create a list of URIs, get a File,
     * and set its permissions
     */
    private Uri[] mFileUris = new Uri[10];
    String transferFile = "transferimage.jpg";
    File extDir = getExternalFilesDir(null);
    File requestFile = new File(extDir, transferFile);
    requestFile.setReadable(true, false);
    // Get a URI for the File and add it to the list of URIs
    fileUri = Uri.fromFile(requestFile);
    if (fileUri != null) {
        mFileUris[0] = fileUri;
    } else {
        Log.e("My Activity", "No File URI available for file.");
    }
    
  • 上記ファイルURIの取得は、Uriにより行う.fromFile()メソッド
  • 上記のコードはAndroid Beamの一部を使用しているだけで、もっと知りたいならBeaming NDEF Messages to Other Devicesを見てください.

  • 2.他装置からのファイル受信
    2.1展示データの要求に応える
    Android Beamが質問ファイルを転送すると、actionからACTION_VIEW、MIMEタイプは、最初のファイルのファイルタイプと、最初のファイルのURIとからなる.ユーザがこのnotificationをクリックすると、このintentが発行される.アプリを鳴らすにはmanifestの対応するActivityの下にラベルを追加する必要があります.次の例を示します.
     
         ...
         
             
             
             ...
         
     
    

    2.2ファイル読み込み権限の要求
     
    

    2.3コピーしたファイルのパスを取得する
    Android Beamは、コピーされたすべてのファイルを1つのパスの下に配置します.上記のintentには最初のファイルのURIが含まれていますが、あなたのappはAndroid Beamではなく他のappによって起動される可能性があります.他のappを起動するintentが持っているURIは異なるフォーマットである可能性があります.そのため、Uriのschemeとauthorityを判断して、どのように処理するかを決定します.
    public class MainActivity extends Activity {
        ...
        // A File object containing the path to the transferred files
        private File mParentPath;
        // Incoming Intent
        private Intent mIntent;
        ...
        /*
         * Called from onNewIntent() for a SINGLE_TOP Activity
         * or onCreate() for a new Activity. For onNewIntent(),
         * remember to call setIntent() to store the most
         * current Intent
         *
         */
        private void handleViewIntent() {
            ...
            // Get the Intent action
            mIntent = getIntent();
            String action = mIntent.getAction();
            /*
             * For ACTION_VIEW, the Activity is being asked to display data.
             * Get the URI.
             */
            if (TextUtils.equals(action, Intent.ACTION_VIEW)) {
                // Get the URI from the Intent
                Uri beamUri = mIntent.getData();
                /*
                 * Test for the type of URI, by getting its scheme value
                 */
                if (TextUtils.equals(beamUri.getScheme(), "file")) {
                    mParentPath = handleFileUri(beamUri);
                } else if (TextUtils.equals(
                        beamUri.getScheme(), "content")) {
                    mParentPath = handleContentUri(beamUri);
                }
            }
            ...
        }
        ...
    }
    

    2.3.1 file URIの処理
    File URIには、ファイルの絶対パスとファイル名が含まれています.次のように処理されます.
        ...
        public String handleFileUri(Uri beamUri) {
            // Get the path part of the URI
            String fileName = beamUri.getPath();
            // Create a File object for this filename
            File copiedFile = new File(fileName);
            // Get a string containing the file's parent directory
            return copiedFile.getParent();
        }
        ...
    

    2.3.2 Content URIの処理
    intentがcontent URIを含む場合、そのURIが指すファイルのパスとファイル名はMediaStoreに存在する可能性がある.URIのauthorityの値をテストしてMediaStoreから来たかどうかを判断することができます.MediaStoreのURIはAndroid Beamから送られてきたのかもしれないし、他のappから送られてきたのかもしれないが、どちらもパスとファイル名を得ることができる.URIのauthorityからcontent providerのタイプを判断し、対応する処理を行います.
        ...
        public String handleContentUri(Uri beamUri) {
            // Position of the filename in the query Cursor
            int filenameIndex;
            // File object for the filename
            File copiedFile;
            // The filename stored in MediaStore
            String fileName;
            // Test the authority of the URI
            if (!TextUtils.equals(beamUri.getAuthority(), MediaStore.AUTHORITY)) {
                /*
                 * Handle content URIs for other content providers
                 */
            // For a MediaStore content URI
            } else {
                // Get the column that contains the file name
                String[] projection = { MediaStore.MediaColumns.DATA };
                Cursor pathCursor =
                        getContentResolver().query(beamUri, projection,
                        null, null, null);
                // Check for a valid cursor
                if (pathCursor != null &&
                        pathCursor.moveToFirst()) {
                    // Get the column index in the Cursor
                    filenameIndex = pathCursor.getColumnIndex(
                            MediaStore.MediaColumns.DATA);
                    // Get the full file name including path
                    fileName = pathCursor.getString(filenameIndex);
                    // Create a File object for the filename
                    copiedFile = new File(fileName);
                    // Return the parent directory of the file
                    return new File(copiedFile.getParent());
                 } else {
                    // The query didn't work; return null
                    return null;
                 }
            }
        }
        ...
    

    Reference
  • Sharing Files with NFC
  • Sending Files to Another Device
  • Receiving Files from Another Device