为什么 Android Beam/NFC 没有收到我发送的记录?
Why isn't Android Beam/NFC receiving the records that I send?
我已经阅读了几次文档并查看了示例代码,但我似乎无法弄清楚我做错了什么。
每当我将我的两个设备放在一起时,我都会看到 Beam 屏幕并点击它,但似乎没有发送任何内容并且 none 我的断点被击中。
这是我的代码,请帮我弄清楚为什么什么都没有发送到其他设备。在编辑器中,我可以看到 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:这是一个单独的 activity,仅显示传送数据的说明并进行实际传送。
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);
}
您发送的 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 类型一样)转换为 小写 大小写。由于您的 Intent 过滤器包含大写字母 "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 包名称格式)。
我已经阅读了几次文档并查看了示例代码,但我似乎无法弄清楚我做错了什么。
每当我将我的两个设备放在一起时,我都会看到 Beam 屏幕并点击它,但似乎没有发送任何内容并且 none 我的断点被击中。
这是我的代码,请帮我弄清楚为什么什么都没有发送到其他设备。在编辑器中,我可以看到 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:这是一个单独的 activity,仅显示传送数据的说明并进行实际传送。
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);
}
您发送的 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 类型一样)转换为 小写 大小写。由于您的 Intent 过滤器包含大写字母 "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 包名称格式)。