【问题标题】:Android NFC foreground dispatch problemAndroid NFC前台调度问题
【发布时间】:2011-08-22 10:27:42
【问题描述】:

我对 android 开发完全陌生,必须编写一个简单的应用程序来读取大学的 nfc 标签(带有 nexus s)。

我的问题是,当 nexus 发现标签时,我的应用程序未列在“选择操作”-弹出窗口中。目的是使用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);
}
}

我尝试了很多,但没有任何效果。如果有人能告诉我我错过了什么,那就太好了。我没时间了:-(

谢谢

【问题讨论】:

    标签: android nfc foreground dispatch


    【解决方案1】:

    前台调度明确要求使用正确配置的 Activity:看起来您不能使用 AndroidManifest.xml 中设置的IntentFilters 进行前台调度(您的应用程序实际上必须在前台,即跑步)。如果您仍然感兴趣(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+"}");
    }
    

    【讨论】:

    • 应该是mTechLists = new String[][] { new String[] { NfcF.class.getName() }, new String[] { NfcB.class.getName() }, new String[] { NfcA.class.getName() }, new String[] { NfcV.class.getName() }, };
    【解决方案2】:

    您的清单文件需要在单独的技术过滤器 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,而技术列表节点的行为类似于 AND。我建议您首先使用 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()}};
    
        }
    

    您必须在 Pause 和 Resume 方法中启用和禁用此功能。 希望这些信息对您有所帮助。

    【讨论】:

    • 无论如何,有没有什么办法不在java文件中添加我的技术列表并在发送未决意图时在此处引用我的xml??
    • @matiasnj 你确定你的AndroidManifest.xmlres/xml/nfc_tech_filter.xml 代码是前台调度所必需的吗??
    • 老实说,这段代码是 5 年前的,我没有在新的 android 开发平台中尝试过。到了这个时候,当 NFC 发展壮大时,答案是肯定的,你需要它们。
    【解决方案3】:

    intent-filter 元素中缺少类别元素?见

    Android NFC: can we use intent filter with mime type? (android 2.3.3)

    您也可以尝试在代码中完全不使用 IntentFilter。

    【讨论】:

    • 我在没有任何意图过滤器的情况下尝试了它,并尝试添加类别元素。它不起作用。
    【解决方案4】:

    如果您启动 Activity 并注册foregroudn调度,您所要做的就是为 ACTION_TAG_DISCOVERED 注册一个意图过滤器 - 这是最低过滤器并匹配所有发现的标签。如果您想更具体一些,您可以为标签技术或包含 ndef 的标签注册一个意图过滤器。

    但是,如果您想通过点击标签从主屏幕启动您的应用程序,您必须以不同的方式执行此操作。我成功地将 mime 消息放到标签上,并将该 mime 类型注册到我的活动中。另一种方法是将 URL 放入标签,然后注册一个意图过滤器来计算方案和主机。对于 mime,这就是您所需要的:

    要进行这种匹配,标签需要有一个带有 mime 的 NDEF mime 消息,如所述。

    【讨论】:

      猜你喜欢
      • 2012-05-03
      • 2018-01-24
      • 1970-01-01
      • 2014-07-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多