12/08/2018, 12:49

Share file với NFC trong android

Với Android Beam, Android cho phép chúng ta chuyển các file với dữ liệu lớn giữa các thiết bị. Tính năng này có 1 API đơn giản, và cho phép người dùng bắt đầu tiến trình chuyển chỉ bằng 1 cú chạm vào thiết bị. Trong phản hồi, Android Beam tự động copy file từ 1 thiết bị sang các thiết khác, và ...

Với Android Beam, Android cho phép chúng ta chuyển các file với dữ liệu lớn giữa các thiết bị. Tính năng này có 1 API đơn giản, và cho phép người dùng bắt đầu tiến trình chuyển chỉ bằng 1 cú chạm vào thiết bị. Trong phản hồi, Android Beam tự động copy file từ 1 thiết bị sang các thiết khác, và thông báo cho người dùng biết khi tiến trình kết thúc.

Trong khi Android Beam file tranfer API xử lí 1 dữ liệu lớn của data, Android Beam NDEF tranfer API được giới thiệu ở Android 4.0(API 14) chỉ có thể gửi các dữ liệu nhỏ như Uris hoặc các tin nhắn nhỏ. Hơn nữa, chỉ có duy nhất Android Beam trong các tính năng của Android NFC framework cho phép đọc NFC message từ các thẻ NFC.

  1. Gửi file đến thiết bị khác Bài này sẽ chỉ cho các bạn thiết kế 1 app để gửi file tới thiết bị khác sử dụng Android Beam file tranfer. Để gửi file, bạn cần gửi 1 yêu cầu để sử dụng NFC và external storage, kiểm tra chắc chắn rằng thiết bị của bạn có hỗ trợ NFC, và cung cấp các Uri tới Android Beam file transfer.

    Android Beam transfer yêu cầu:

    • Android 4.1 (API 16) hoặc cao hơn.

    • File muốn gửi phải ở bộ nhớ ngoài.

    • Mỗi file muốn gửi phải là world-readable. Có thể cài permission này với lệnh : File.setReadable(true,false)

    • Phải gửi 1 file Uri cho file bạn muốn chuyển. Android Beam file transfer không thể gửi 1 file với Uri được gọi bởi: FileProvider.getUriForFile

    1.1 Yêu cầu các quyền

    NFC:

    <uses-permission android:name="android.permission.NFC" />
Bộ nhớ ngoài:
       <uses-permission
            android:name="android.permission.READ_EXTERNAL_STORAGE" />
Xác định tính năng NFC
    <uses-feature
    android:name="android.hardware.nfc"
    android:required="true" />
Đặt minSDKversion là 16 với cả thiết bị của bạn và thiết bị bạn muốn nhận file.

1.2 Tạo 1 Callback để cung cấp file

Thêm 1 call back để phát hiện khi người dùng muốn gửi 1 file đến 1 thiết bị khác:
    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;
            }
        }
        ...
    }
Cung cấp callback tới AndroidBeam bằng cách gọi 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);
            ...
        }
        ...
    }
1.3 Xác định file để gửi

Để gửi 1 hoặc nhiều file tới 1 thiết bị khác, lấy 1 file Uri (1 Uri đã được sắp xếp) với mỗi file, sau đó thêm các Uri vào 1 mảng các đối tượng Uri. Để gửi 1 file, bạn cũng cần có 1 sự truy cập thường xuyên cho file đó:
    /*
    * 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.");
    }
  1. Nhận file từ thiết bị khác

    2.1 Đáp ứng một yêu cầu để hiển thị dữ liệu:

    Sau khi Android Beam file transfer hoàn thành việc gửi 1 file tới 1 thiết bị, nó sẽ gửi 1 notification chứa 1 Intent với action là ACTION_VIEW, kiểu MIME của file đầu tiên được gửi.

    Để có được phản hồi của Intent này, bạn cần thêm 1 <inten-filter> vào trong activity:

    <action android:name="android.intent.action.VIEW" />
    <category android:name="android.intent.category.CATEGORY_DEFAULT" />
    <data android:mimeType="mime-type" />
Phù hợp với kiểu MIME, cần xác định các kiểu MIME mà app của bạn có thể xử lí.
Ví dụ với 1 activity có tên ViewActivity:
    <activity
        android:name="com.example.android.nfctransfer.ViewActivity"
            android:label="Android Beam Viewer" >
            ...
            <intent-filter>
                <action android:name="android.intent.action.VIEW"/>
                <category android:name="android.intent.category.DEFAULT"/>
                ...
            </intent-filter>
    </activity>
2.2 Yêu cầu các permission
    <uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
Nếu bạn muốn sao chép các tập tin chuyển đến khu vực lưu trữ riêng của ứng dụng của bạn, yêu cầu permission WRITE_EXTERNAL_STORAGE thay thế WRITE_EXTERNAL_STORAGE bao gồm READ_EXTERNAL_STORAGE.

2.3 Lấy đường dẫn cho file

ứng dụng của bạn có thể nhận được một ý định ACTION_VIEW từ một nguồn khác với Android Beam. Để xác định cách bạn nên xử lý Intent đến, bạn cần phải kiểm tra scheme và authority của nó.
Để lấy scheme cho Uri, gọi đến hàm Uri.getscheme:
    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.4 Lấy directory từ 1 file URI

Nếu Intent có chứa 1 file Uri, file Uri có chứa file name của 1 file, với đầy đủ đường dẫn và tên file. Các đường dẫn trỏ đến 1 vị trí của file được gửi đến khác. Để lấy đường dẫn, lấy đường dẫn của Uri chứa tất cả Uri, trừ prefix. Tạo 1 file từ đường dẫn này, gọi cha của nó:
    ...
    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.5 Xác định content provider

Để xác định xem bạn có thể truy xuất một thư mục tập tin từ các nội dung URI, xác định các nhà cung cấp nội dung có liên quan với các URI bằng cách gọi Uri.getAuthority () để có được quyền của URI. Kết quả có hai giá trị: MediaStore.AUTHORITY
URI là một tập tin hoặc các tập tin theo dõi bởi MediaStore. Lấy tên tập tin đầy đủ từ MediaStore, và nhận được thư từ tên tập tin.

Giá trị bất kỳ authority nào khác

Một nội dung URI từ một nhà cung cấp nội dung. Hiển thị các dữ liệu liên quan đến nội dung URI, nhưng không nhận được thư mục file.

Để có được các thư mục cho một nội dung MediaStore URI, chạy một truy vấn mà xác định các nội dung URI đến cho các đối số Uri và cột MediaColumns.DATA để chiếu. Cursor trả lại chứa các đường dẫn đầy đủ và tên cho các tập tin được đại diện bởi các URI. Con đường này cũng có chứa tất cả các file khác mà Android Beam chuyển tập tin chỉ cần sao chép các thiết bị.
    ...
    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;
             }
        }
    }
    ...
0