【问题标题】:Why isn't Android Beam/NFC receiving the records that I send?为什么 Android Beam/NFC 没有收到我发送的记录?
【发布时间】:2016-10-04 02:51:41
【问题描述】:

我已经阅读了几次文档并查看了示例代码,但我似乎无法弄清楚我做错了什么。

每当我将两个设备放在一起时,我都会看到 Beam 屏幕并点击它,但似乎没有发送任何内容,也没有遇到断点。 这是我的代码,请帮我弄清楚为什么没有任何东西发送到其他设备。在编辑器中,我可以看到BeamFileActivity 中的所有内容都在运行,我只是从未看到MainActivity 中的任何断点在接收设备上被访问。我做错了什么?

AndroidManifest.xml:

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.myapp">
    <uses-permission android:name="android.permission.NFC" />
    <uses-feature android:name="android.hardware.nfc" android:required="true" />
    <application
    android:name=".MainActivity"
    android:allowBackup="true"
    android:icon="@drawable/ic_launcher"
    android:label="@string/app_name"
    android:theme="@style/AppTheme">
        <meta-data
            android:name="QUERY_LOG"
            android:value="false" />
        <meta-data
            android:name="DOMAIN_PACKAGE_NAME"
            android:value="com.myapp.domain" />

        <activity
            android:name=".MainActivity"
            android:exported="true"
            android:label="@string/app_name"
            android:windowSoftInputMode="adjustResize">

            <intent-filter>
                <action android:name="com.google.android.apps.drive.DRIVE_OPEN" />
                <action android:name="com.google.android.apps.drive.DRIVE_SAVE" />
                <data android:mimeType="application/vnd.google-apps.drive-sdk.111111111" />
                <data android:mimeType="application/vnd.google-apps.spreadsheet" />
                <action android:name="android.intent.action.MAIN" />
                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
            <intent-filter>
                <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
                <category android:name="android.intent.category.DEFAULT"/>
                <data android:scheme="vnd.android.nfc"
                    android:host="ext"
                    android:pathPrefix="/com.myapp:SpreadsheetDom"/>
            </intent-filter>
        </activity>
        <activity
            android:name=".dialog.BeamFileActivity"
            android:label="@string/title_activity_beam_file"
            android:parentActivityName=".MainActivity"
            android:theme="@style/AppTheme.NoActionBar">
            <meta-data
                android:name="android.support.PARENT_ACTIVITY"
                android:value="com.myapp.MainActivity" />
        </activity>
    </application>

MainActivity:这是接收 Beam 意图的内容,我只包括我认为相关的方法。

@Override
protected void onResume() {

    super.onResume();

    //I removed some code that reloads my application, didn't seem relevant

    if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) {
        processIntent(getIntent());
    }
}

/**
 * Parses the NDEF Message from the intent and stores the collection
 */
void processIntent(Intent intent) {

    Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
    // only one message expected during the beam
    NdefMessage msg = (NdefMessage) rawMsgs[0];

    //This is the data I'm beaming, It has a method that converts its data to a byte array, and a method, fromBytes() that converts bytes into the object
    SpreadsheetDom dom = new SpreadsheetDom();
    try {

        for(int i = 0; i < msg.getRecords().length; i++) {

            if(SpreadsheetDom.class.getName().equalsIgnoreCase(new String(msg.getRecords()[i].getType()))) {

                dom.fromBytes(msg.getRecords()[i].getPayload());
                //removed some code that saves and displays changes
            }
        }
    } catch(IOException | ClassNotFoundException e) {

    }
}

@Override
public void onNewIntent(Intent intent) {

    setIntent(intent);
}

BeamFileActivity:这是一个单独的活动,仅显示发送数据的指令并执行实际的发送。

private void initFileToBeam(Long spreadsheetId) {

    try {

        List<SpreadsheetDom> spreadsheets = db.getSpreadsheetDao().queryForEq(SpreadsheetDom.SPREADSHEET_ID_NAME, spreadsheetId);
        if(spreadsheets != null && spreadsheets.size() > 0) {

            fileToBeam = spreadsheets.get(0);
        }
    } catch(SQLException e) {

        ErrorDialog ed = new ErrorDialog(this, "Unable to beam current collection.");
        ed.show();
    }
}

@Override
public NdefMessage createNdefMessage(NfcEvent event) {

    if(fileToBeam == null) {

        Long spreadsheetId = Settings.getInstance().get(SettingKey.CURRENT_SPREADSHEET).getValue();
        initFileToBeam(spreadsheetId);
    }

    NdefMessage msg = null;
    try {

        msg = new NdefMessage(
                new NdefRecord[]{
                        new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE, "application/com.myapp:SpreadsheetDom".getBytes(), new byte[0], fileToBeam.toBytes()),
                        //NdefRecord.createExternal("com.myapp", "spreadsheetdom", fileToBeam.toBytes()),
                        NdefRecord.createApplicationRecord("com.myapp")
                });
    } catch(IOException e) {

        String textMessage = "Unable to transfer collection: " + e.getMessage();
        msg = new NdefMessage(
                new NdefRecord[]{
                        NdefRecord.createMime("text/plain", textMessage.getBytes()),
                        NdefRecord.createApplicationRecord("com.myapp")
                });
    }

    return msg;
}

@Override
public void onResume() {

    super.onResume();

    Intent exportFileIntent = getIntent();
    Long spreadsheetId = exportFileIntent.getLongExtra(Constants.EXTRA_SPREADSHEET_ID, Database.INVALID_ID);

    initFileToBeam(spreadsheetId);

    mNfcAdapter = NfcAdapter.getDefaultAdapter(this);
    if (mNfcAdapter == null) {

        Toast.makeText(this, "NFC is not available", Toast.LENGTH_LONG).show();
        finish();
        return;
    }
    // Register callback
    mNfcAdapter.setNdefPushMessageCallback(this, this);
}

所有这些都来自示例和文档hereherehere

【问题讨论】:

    标签: android nfc ndef nfc-p2p android-beam


    【解决方案1】:

    您发送的 NDEF 记录与您的 MainActivity 期望的不同。您的 MainActivity 已注册 NFC 论坛外部类型“com.myapp:SpreadsheetDom”:

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="vnd.android.nfc"
              android:host="ext"
              android:pathPrefix="/com.myapp:SpreadsheetDom"/>
    </intent-filter>
    

    由于 Android 中的 Intent 过滤器区分大小写,但 NFC 论坛外部类型名称不区分大小写,Android 会自动转换 NFC 论坛外部类型的名称(就像MIME 类型)转为 小写。由于您的意图过滤器包含大写字母“S”和“D”,因此它永远不会匹配您的 NFC 论坛外部类型的类型名称。因此,您必须将类型名称指定为全小写以实现匹配(另请参阅here):

    <intent-filter>
        <action android:name="android.nfc.action.NDEF_DISCOVERED"/>
        <category android:name="android.intent.category.DEFAULT"/>
        <data android:scheme="vnd.android.nfc"
              android:host="ext"
              android:pathPrefix="/com.myapp:spreadsheetdom"/>
    </intent-filter>
    

    接下来,在您的BeamFileActivity 中创建一个类型名称无效的外部记录“application/com.myapp:SpreadsheetDom”:

    msg = new NdefMessage(new NdefRecord[] {
            new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE, "application/com.myapp:SpreadsheetDom".getBytes(), new byte[0], fileToBeam.toBytes()),
            NdefRecord.createApplicationRecord("com.myapp")
    });
    

    与上述意图过滤器匹配的 NFC 论坛外部类型名称将是“com.myapp:spreadsheetdom”(同样,所有小写字母)。您可以使用以下命令创建这样的记录(确保对类型名称使用 US-ASCII 编码):

    msg = new NdefMessage(new NdefRecord[] {
            new NdefRecord(NdefRecord.TNF_EXTERNAL_TYPE, "com.myapp:spreadsheetdom".getBytes("US-ASCII"), new byte[0], fileToBeam.toBytes()),
            NdefRecord.createApplicationRecord("com.myapp")
    });
    

    最后,请注意,根据 NFC 论坛记录类型定义,“com.myapp”不是外部类型的格式正确的域名。相反,格式正确的域名应该是“myapp.com”(Internet 域名格式而不是 Java 包名格式)。

    【讨论】:

    • 我进行了您建议的更改,但仍然无法正常工作。我切换到一个简单的文本消息并将类型更改为 TNF_MIME_MEDIA 并且我能够获取要传输的数据。但是,当我切换回我的电子表格时,它停止工作,似乎问题可能出在大小上。我将电子表格域转换为 bytearrayoutputstream 并填充该对象中的 9 个缓冲区。不知道是不是很多,好像很多。您可以通过 TNF_MIME_MEDIA 消息发送的数据量是否有限制?
    • @Hardy 您的数据块有多大(以字节为单位)?外部类型是否适用于简单的文本消息?
    • 当我尝试外部类型时,它总是会进入 Play 商店并且永远不会打开我的应用程序。 byteArrayOutputStream.size() 报告 322,000
    • @Hardy 关于外部类型和前往 Play 商店:您是否对外部类型和 MIME 类型/简单文本消息使用相同的 AAR (NdefRecord.createApplicationRecord("com.myapp"))?进入 Play 商店的设备表明您在 AAR 中使用了错误的包名称。
    • 我想我会仔细检查我们讨论过的所有内容,以及当我完成所有工作时。所以我不知道我之前做错了什么,但你上面的建议现在对我有用。第一次阅读您的答案后我所拥有的与我现在所拥有的唯一区别是我压缩了字节数组。也许在没有压缩到位之前有些事情已经超时了?身份证。再次感谢您的帮助。
    猜你喜欢
    • 2013-03-26
    • 1970-01-01
    • 1970-01-01
    • 2013-05-17
    • 2018-03-27
    • 2022-11-11
    • 2016-04-10
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多