Android获取NFC标签和NFC十进制16进制ID

Posted

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Android获取NFC标签和NFC十进制16进制ID相关的知识,希望对你有一定的参考价值。

参考技术A <uses-feature

    android:name="android.hardware.nfc"

    android:required="true"/>

<uses-permission android:name="android.permission.NFC"/>

```

class NfcActivity :BaseActivity()

private lateinit var imgBack:ImageView

    private lateinit var mNfcAdapter:NfcAdapter

    private lateinit var mPendingIntent:PendingIntent

    //nfc标签信息

    private lateinit var tvNfcTag:TextView

    //nfc十进制ID

    private lateinit var tvNfcD:TextView

    //nfc16进制ID

    private lateinit var tvNfcH:TextView

    /**

    * 启动Activity

*/

    override fun onStart()

super.onStart()

mNfcAdapter =NfcAdapter.getDefaultAdapter(this)

//一旦截获NFC消息,就会通过PendingIntent调用窗口

        mPendingIntent =PendingIntent.getActivity(this,0,Intent(this,javaClass),0)



override fun getLayoutId():Int

return R.layout.activity_nfc

   

override fun eventBus(event:Any?)



override fun onCreate(savedInstanceState:Bundle?)

super.onCreate(savedInstanceState)

imgBack =findViewById(R.id.img_nfc_back)

tvNfcD =findViewById(R.id.tv_nfc_d)

tvNfcH =findViewById(R.id.tv_nfc_h)

tvNfcTag =findViewById(R.id.tv_nfc_tag)

imgBack.setOnClickListener finish()



override fun onResume()

super.onResume()

//设置处理优于所有其他NFC的处理

        mNfcAdapter.enableForegroundDispatch(

this,

mPendingIntent,

null,

null

        )



override fun onPause()

super.onPause()

//恢复默认状态

        mNfcAdapter.disableForegroundDispatch(this)



override fun onNewIntent(intent:Intent?)

super.onNewIntent(intent)

//        readFromTag(intent);

        readNfcTag(intent!!)



/**

    * 读取NFC标签文本数据

    */

    private fun readNfcTag(intent:Intent)

val tag:Tag? =intent.getParcelableExtra(NfcAdapter.EXTRA_TAG)

if (tag !=null)

val cardNo =flipHexStr(ByteArrayToHexString(tag.id)).toLong(16)

tvNfcD.text = cardNo.toString()

tvNfcH.text =ByteArrayToHexString(tag.id)



if (NfcAdapter.ACTION_NDEF_DISCOVERED ==intent.action)

val rawMessages =intent.getParcelableArrayExtra(

NfcAdapter.EXTRA_NDEF_MESSAGES

            )

var msgs:Array? =null

            var contentSize =0

            if (rawMessages !=null)

msgs =arrayOfNulls(rawMessages.size)

for (iin rawMessages.indices)

msgs[i] = rawMessages[i]as NdefMessage

                    contentSize +=msgs[i]!!.toByteArray().size

               



try

if (null !=msgs)

val record =msgs[0]!!.records[0]

val textRecord:String? =

NfcUtil.parseTextRecord(record)

Log.e("nfcTag-->","" + textRecord)

tvNfcTag.text = textRecord



catch (e:Exception)

e.printStackTrace()

Log.e("nfcError-->","" + e)









```

获取标签及其ID的工具类

import android.nfc.NdefRecord;

import java.nio.charset.StandardCharsets;

import java.util.Arrays;

public class NfcUtil

/**

    * 解析NDEF文本数据,从第三个字节开始,后面的文本数据

    * @param ndefRecord

    * @return

    */

    public static String parseTextRecord(NdefRecord ndefRecord)

/**

        * 判断数据是否为NDEF格式

        * 判断TNF

*/

        if (ndefRecord.getTnf() !=NdefRecord.TNF_WELL_KNOWN)

return null;



//判断可变的长度的类型

        if (!Arrays.equals(ndefRecord.getType(),NdefRecord.RTD_TEXT))

return null;



try

//获得字节数组,然后进行分析

            byte[] payload =ndefRecord.getPayload();

//下面开始NDEF文本数据第一个字节,状态字节

            //判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1,

            //其他位都是0,所以进行"位与"运算后就会保留最高位

            String textEncoding = ((payload[0] &0x80) ==0) ?"UTF-8" :"UTF-16";

//3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位

            int languageCodeLength = payload[0] &0x3f;

//下面开始NDEF文本数据第二个字节,语言编码

            //获得语言编码

            String languageCode =new String(payload,1, languageCodeLength,StandardCharsets.US_ASCII);

//下面开始NDEF文本数据后面的字节,解析出文本

            String textRecord =new String(payload, languageCodeLength +1,

payload.length - languageCodeLength -1, textEncoding);

return textRecord;

catch (Exception e)

throw new IllegalArgumentException();





// 16转10进制

    public static String flipHexStr(String s)

StringBuilder result =new StringBuilder();

for (int i =0; i <=s.length() -2; i = i +2)

result.append(new StringBuilder(s.substring(i, i +2)).reverse());



return result.reverse().toString();



public static String ByteArrayToHexString(byte[]inarray)

int i, j, in;

String[] hex = "0","1","2","3","4","5","6","7","8","9","A",

"B","C","D","E","F";

StringBuilder out =new StringBuilder();

for (j =0; j

in = (int)inarray[j] &0xff;

i = (in >>4) &0x0f;

out.append(hex[i]);

i = in &0x0f;

out.append(hex[i]);



return out.toString();



如何通过 NFC 标签启动我的应用程序?

【中文标题】如何通过 NFC 标签启动我的应用程序?【英文标题】:How to launch my app via NFC tag? 【发布时间】:2016-03-17 06:20:49 【问题描述】:

我目前正在将应用移植到 UWP。该应用程序有一个带有“写入 NFC”按钮的页面。用户点击后,它会等待 NFC 标签并写入LaunchApp:WriteTag 二进制消息。

在 WP8.1 下运行良好,在 Windows 10 UWP 下根本无法运行:

var proximityDevice = Windows.Networking.Proximity.ProximityDevice.GetDefault();

if (proximityDevice != null)

    var launchArgs = "user=default";

    var appId = "App";
    var appName = Windows.ApplicationModel.Package.Current.Id.FamilyName + "!" + appId;

    var launchAppMessage = launchArgs + "\tWindows\t" + appName;

    var dataWriter = new Windows.Storage.Streams.DataWriter();
    dataWriter.UnicodeEncoding = Windows.Storage.Streams.UnicodeEncoding.Utf16LE;
    dataWriter.WriteString(launchAppMessage);
    var launchAppPubId = proximityDevice.PublishBinaryMessage("LaunchApp:WriteTag", dataWriter.DetachBuffer());

不幸的是,这不起作用。 NFC 功能已启用且 WP8.1 应用程序可在同一部手机上运行,​​因此这应该不是问题。

我已经尝试了多种格式,因为问题似乎是 launchAppMessage,我没有找到 UWP 文档。有一篇Windows 8+MSDN 文章,描述了字符串的格式:

myArgs\tWindows\tAppFamilyName!App

我尝试了什么:

    myArgs 足够短 - 应该不是问题。 WindowsWindowsPhone 没有任何区别。两者都不起作用。 AppFamilyName 是我的应用清单中的正确应用系列名称。该应用与商店相关联,看起来这也不应该是问题。 App 是我的应用清单中 &lt;Application id="App" ... /&gt; 的内容。尝试 MyAppNamespace.App 效果不佳,调用 CurrentApp.AppId(在 WinRT 应用程序中使用)会引发异常。

“不工作”是指它写入标签,但 Windows 10 根本无法识别标签。

我发现的另一件事是,对于myArgs\tWindows\tAppFamilyName!App,应用程序抛出以下异常 - 没有任何进一步的细节:

System.ExecutionEngineException was unhandled
Message: An unhandled exception of type 'System.ExecutionEngineException' occurred in Unknown Module.

我真的希望有人知道如何解决这个问题。不幸的是,目前还没有 UWP 示例,文档仍然是旧的......:/

PS:将自定义协议与 WindowsUri:WriteTag 一起使用可以正常工作,但我希望只使用 NFC 标签打开我的应用程序。此外,确认对话框看起来像“您要打开与 mycustomprotocol 关联的应用程序吗?” - 这看起来不是很用户友好。所以这对我来说不是真正的解决方案,更多的是我不想使用的解决方法。

【问题讨论】:

【参考方案1】:

Windows 10 移动版 UWP

如果您只针对 Windows 10 移动版,8.1 方式仍然有效,前提是您获得了正确的 App ID。可以通过以下方式检索:

Windows.ApplicationModel.Store.CurrentApp.AppId

但是,这仅在通过商店安装应用时有效,因为 ID 是在商店关联/发布期间分配的。在开发人员部署的构建中,API 将因“HRESULT 异常:0x803F6107”而崩溃。

然后,生成的 LaunchApp 记录需要平台“WindowsPhone”和该应用 ID。以下代码通过开源 NFC / NDEF 库 (https://github.com/andijakl/ndef-nfc) 创建一个 LaunchApp 标签,适用于 Windows 10 移动版 - 用于编写标签和启动应用程序。再次 - 鉴于它已通过商店发布和安装:

var record = new NdefLaunchAppRecord  Arguments = "Hello World" ;
var appId = Windows.ApplicationModel.Store.CurrentApp.AppId;    // Note: crashes when app is not installed through app store!
record.AddPlatformAppId("WindowsPhone", appId);
var message = new NdefMessage  record ;
proximityDevice.PublishBinaryMessage("NDEF:WriteTag", msgArray.AsBuffer(), MessageWrittenHandler);

Windows 10 电脑

不幸的是,PC 的情况有所不同。上面的方法在那里不起作用,Windows 8.1 的记录方法也不起作用。

到目前为止,我能做到的最接近的方法是让 Windows 10 识别 LaunchApp 标签并在正确的页面上打开商店。但是Windows/商店没有意识到该应用程序已经安装,因此没有打开它。

这是代码,再次使用 NFC / NDEF 库:

var record = new NdefLaunchAppRecord  Arguments = "Hello World" ;
var familyName = Windows.ApplicationModel.Package.Current.Id.FamilyName;
var appId = Windows.ApplicationModel.Store.CurrentApp.AppId;    // Note: crashes when app is not installed through app store!
record.AddPlatformAppId("Windows", "" + familyName + "!" + appId + "");
var message = new NdefMessage  record ;
proximityDevice.PublishBinaryMessage("NDEF:WriteTag", msgArray.AsBuffer(), MessageWrittenHandler);

当然,如果您有足够的可写内存,您也可以将两个平台 ID 组合到一个 NFC 标签中,因为这些应用 ID 很大。

【讨论】:

谢谢安德烈亚斯!我已经在您的代码中看到了我的 SO 问题的链接,所以感谢您的详细回答:) 我认为这里真正的问题是如果应用程序没有通过商店安装,则会引发异常,所以让我们看看 MS 是否可以这样做someone from the NFC team of MSFT answered in my MSDN forum thread about this problem。 很高兴看到这一点,感谢您的链接!我还在跟进我们的 MVP 邮件列表 - 当我们从 MS 得到明确答复时,让我们保持更新 SO 帖子!【参考方案2】:

这是一种方法:

    注册后台任务并使用 NFC 触发器 注册您的应用以激活 uri。

    将后台任务编程为在使用 NFC 标签点击时激活,然后启动应用 URI 方案

    //设置推荐应用

    var options = new Windows.System.LauncherOptions();
    options.PreferredApplicationPackageFamilyName= "Contoso.URIApp_8wknc82po1e";
    options.PreferredApplicationDisplayName = "Contoso URI Ap";
    
    // Launch the URI and pass in the recommended app 
    // in case the user has no apps installed to handle the URI
    var success = await Windows.System.Launcher.LaunchUriAsync(uriContoso, options);
    

【讨论】:

请问“NFC 触发器”应该是什么?我找不到任何IBackgroundTaskTrigger 会在找到 NFC 标签时触发? 您同时回答了其他几个问题,我猜您在这里也不知道您的“答案”......太糟糕了。 :/ 我希望其他人可以提供帮助。 我试图找到解决方案。我遇到了 sensordatathreshold 触发器的这个触发器,但不幸的是我没有启用 NFC 的 WINdows 设备来测试或实验这个..所以我现在无法进一步帮助你..有一个艰难的方法,但我不值得痛苦..它正在构建自定义触发器..我认为普通开发人员无法访问它..如果你想采取 lokk 去msdn.microsoft.com/en-us/library/windows/hardware/… 也许您可以尝试研究低级 api 并获取 dll 并围绕它创建一个 c# 包装器并将其用作触发器.. 只是理论.. 未经测试..【参考方案3】:

如果您有一个 WP8.1 应用程序并在 Windows Phone 10 上运行此应用程序,并且想要在您的手机上写入 NFC 标签,您必须检索AppId。这是通过打开Windows Dev Center 打开相应的应用程序,单击App Management,然后单击App identity 来完成的。然后在URL for Windows Phone 8.1 and earlier点下复制GUID并替换Windows.ApplicationModel.Store.CurrentApp.AppId

【讨论】:

以上是关于Android获取NFC标签和NFC十进制16进制ID的主要内容,如果未能解决你的问题,请参考以下文章

NFC在Android中的应用

Broadcom NFC 堆栈对基于二进制读取的存在检查的预期响应

NFC Basics(基本NFC)——翻译自developer.android.com

如何在android中测量NFC RSSI?

如何在android中使用NFC在两个设备之间发送数据?

怎么开发 android nfc所支持的标签技术类型