我对Android开发完全陌生,必须编写一个简单的应用程序来读取大学的nfc标签(使用nexus s)。
我的问题是,当nexus发现一个标签时,我的应用程序没有列在“选择一个动作”-popup中。目的是使用前缀调度方法读取标签,如http://developer.android.com/guide/topics/nfc/index.html中所述 和 http://developer.android.com/resources/samples/ApiDemos/src/com/example/android/apis/nfc/ForegroundDispatch.html
我认为清单中缺少一些东西,但我不知道是什么。 这是清单:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.iforge.android.nfc"
>
<uses-permission android:name="android.permission.INTERNET"></uses-permission>
<uses-permission android:name="android.permission.NFC" />
<uses-permission android:name="android.permission.CALL_PHONE" />
<application
android:icon="@drawable/icon"
android:label="@string/app_name"
>
<activity android:name=".simulator.FakeTagsActivity"
android:theme="@android:style/Theme.NoTitleBar">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity android:name="TagViewer"
android:theme="@android:style/Theme.NoTitleBar"
>
<intent-filter>
<action android:name="android.nfc.action.NDEF_DISCOVERED"/>
<data android:mimeType="mime/type" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
</activity>
</application>
<uses-sdk android:minSdkVersion="10" />
<uses-feature android:name="android.hardware.nfc" android:required="true" />
这是发现标记时应该调用的活动的代码(它是从android NFCDemo以及ForegroundDispatch示例构建的):
public class TagViewer extends Activity
{
WebView webView;
private NfcAdapter mAdapter;
private PendingIntent mPendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
@Override
protected void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
mAdapter = NfcAdapter.getDefaultAdapter(this);
mPendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
}
catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
mFilters = new IntentFilter[] {
ndef,
};
mTechLists = new String[][] { new String[] { NfcF.class.getName() } };
setContentView(R.layout.tag_viewer);
webView = (WebView) findViewById(R.id.webView1);
webView.getSettings().setJavaScriptEnabled(true);
webView.getSettings().setJavaScriptCanOpenWindowsAutomatically(false);
webView.getSettings().setPluginsEnabled(false);
webView.getSettings().setSupportMultipleWindows(false);
webView.getSettings().setSupportZoom(false);
webView.setVerticalScrollBarEnabled(false);
webView.setHorizontalScrollBarEnabled(false);
resolveIntent(getIntent());
}
@Override
public void onResume() {
super.onResume();
mAdapter.enableForegroundDispatch(this, mPendingIntent, mFilters, mTechLists);
}
@Override
public void onPause() {
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
void resolveIntent(Intent intent)
{
// Parse the intent
String action = intent.getAction();
if (NfcAdapter.ACTION_TAG_DISCOVERED.equals(action))
{
// When a tag is discovered we send it to the service to be save. We
// include a PendingIntent for the service to call back onto. This
// will cause this activity to be restarted with onNewIntent(). At
// that time we read it from the database and view it.
Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES);
NdefMessage[] msgs;
if (rawMsgs != null)
{
msgs = new NdefMessage[rawMsgs.length];
for (int i = 0; i < rawMsgs.length; i++)
{
msgs[i] = (NdefMessage) rawMsgs[i];
}
}
else
{
// Unknown tag type
byte[] empty = new byte[] {};
NdefRecord record = new NdefRecord(NdefRecord.TNF_UNKNOWN, empty, empty, empty);
NdefMessage msg = new NdefMessage(new NdefRecord[] {record});
msgs = new NdefMessage[] {msg};
}
// Setup the web-view
setUpWebView(msgs);
}
else
{
Log.e("ViewTag", "Unknown intent " + intent);
finish();
return;
}
}
void setUpWebView(NdefMessage[] msgs)
{
if (msgs == null || msgs.length == 0) return;
String urlToLoad = MessageParser.parseMessage(msgs[0]);
if(!urlToLoad.matches("")) webView.loadUrl(urlToLoad);
}
@Override
public void onNewIntent(Intent intent)
{
setIntent(intent);
resolveIntent(intent);
Log.i("Foreground dispatch", "Discovered tag with intent: " + intent);
}
}
我尝试了很多,但没有任何作用。如果有人能告诉我我错过了什么会很棒。我没时间了: - (
请
感谢
答案 0 :(得分:4)
您的清单文件需要在单独的技术过滤器xml中处理技术发现的意图,如下所示:
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.nfc.action.TECH_DISCOVERED"/>
</intent-filter>
<meta-data android:name="android.nfc.action.TECH_DISCOVERED"
android:resource="@xml/nfc_tech_filter" />
<intent-filter>
<action android:name="android.nfc.action.TAG_DISCOVERED"/>
</intent-filter>
然后你的res / xml / nfc_tech_filter.xml必须像这样处理你想要的nfc技术:
<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
<tech-list>
<tech>android.nfc.tech.MifareUltralight</tech>
<tech>android.nfc.tech.Ndef</tech>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
<tech-list>
<tech>android.nfc.tech.MifareClassic</tech>
<tech>android.nfc.tech.Ndef</tech>
<tech>android.nfc.tech.NfcA</tech>
</tech-list>
</resources>
每个技术节点都像一个AND,而技术列表节点就像和OR一样。我建议您首先使用NFC标签阅读器等工具扫描您的标签,以便了解您的技术人员。
然后在java代码中,您可以启用/禁用您的前台调度系统,就像其他已经技术的网站一样,我设置了与xml中相同的技术,如下所示:
private void setUpForegroundDispatchSystem()
{
this.nfcAdapter = NfcAdapter.getDefaultAdapter(this);
this.pendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*"); /* Handles all MIME based dispatches.
You should specify only the ones that you need. */
ndef.addDataScheme("http");
}
catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
this.intentFiltersArray = new IntentFilter[] {ndef};
this.techListsArray = new String[][] { new String[] { MifareUltralight.class.getName(), Ndef.class.getName(), NfcA.class.getName()},
new String[] { MifareClassic.class.getName(), Ndef.class.getName(), NfcA.class.getName()}};
}
您必须在“暂停”和“恢复”方法中启用和禁用此功能。 希望这些信息对您有所帮助。
答案 1 :(得分:4)
前台调度明确要求使用已正确配置的Activity:看起来您不能使用AndroidManifest.xml中设置的IntentFilter
进行前台调度(您的应用必须实际位于前台) ,即跑步)。以下代码似乎正常工作(我刚刚测试过)以防您仍然感兴趣(ACTION_TAG_DISCOVERED
就是我正在观看的内容):
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
/** Called when the activity is first created. */
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
setContentView(R.layout.main);
mAdapter = NfcAdapter.getDefaultAdapter(this);
pendingIntent = PendingIntent.getActivity(
this, 0, new Intent(this, getClass()).addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP), 0);
// Setup an intent filter for all MIME based dispatches
IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
try {
ndef.addDataType("*/*");
} catch (MalformedMimeTypeException e) {
throw new RuntimeException("fail", e);
}
IntentFilter td = new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED);
mFilters = new IntentFilter[] {
ndef, td
};
// Setup a tech list for all NfcF tags
mTechLists = new String[][] { new String[] {
NfcV.class.getName(),
NfcF.class.getName(),
NfcA.class.getName(),
NfcB.class.getName()
} };
}
@Override
public void onResume()
{
super.onResume();
mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters, mTechLists);
}
@Override
public void onPause()
{
super.onPause();
mAdapter.disableForegroundDispatch(this);
}
@Override
public void onNewIntent(Intent intent){
// fetch the tag from the intent
Tag t = (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
String tlist = getTechList(t);
android.util.Log.v("NFC", "Discovered tag ["+tlist+"]["+t+"] with intent: " + intent);
android.util.Log.v("NFC", "{"+t+"}");
}
答案 2 :(得分:0)
intent-filter元素中缺少类别元素?参见
Android NFC: can we use intent filter with mime type? (android 2.3.3)
您也可以尝试在代码中完全不使用IntentFilter。
答案 3 :(得分:0)
如果启动Activity并注册foregroudn dispatch,您所要做的就是为ACTION_TAG_DISCOVERED注册一个intent过滤器 - 这是最低过滤器并匹配所有发现的标签。如果您想要更具体,您可以为标签技术或包含ndef的标签注册意图过滤器。
但是如果你想通过点击标签从主屏幕启动你的应用程序,你可以采取不同的方式。我成功地将mime消息放到标签上,并将mime类型注册到我的活动中。另一种方法是将URL放到标签上,然后注册一个算法过滤器,用于计算方案和主机。对于哑剧,这就是你需要的:
要进行此匹配,标记需要具有带有mime的NDEF mime消息,如上所述。