編輯:關於Android編程
為了充分詳細的學習nfc相關的知識,決定閱讀官方英文文檔,並翻譯下來供大家閱讀。
NFC Basics
There are two major uses cases when working with NDEF data and Android:
The Tag Dispatch SystemReading NDEF data from an NFC tag
Beaming NDEF messages from one device to another with Android Beam?
Parsing the NFC tag and figuring out the MIME type or a URI that identifies the data payload in the tag.
解析NFC標簽,計算出MINE類型或者一個URI,用於標示數據負載的身份
Encapsulating the MIME type or URI and the payload into an intent. These first two steps are described in How NFC tags are mapped to MIME types and URIs.
封裝MIME類型或者URI和負載放入intent對象,這兩步由 How NFC tags are mapped to MIME types and URIs描述。
Starts an activity based on the intent. This is described in How NFC Tags are Dispatched to Applications.
啟動一個activity根據這個intent對象,這部分由How NFC Tags are Dispatched to Applications.描述
How NFC tags are mapped to MIME types and URIs(NFC標簽是如何映射到MINE類型和URI的?)
Before you begin writing your NFC applications, it is important to understand the different types of NFC tags, how the tag dispatch system parses NFC tags, and the special work that the tag dispatch system does when it detects
an NDEF message. NFC tags come in a wide array of technologies and can also have data written to them in many different ways. Android has the most support for the NDEF standard, which is defined by the NFC Forum.
在你開始寫NFC應用之前,理解不同類型的NFC標簽,標簽調度系統如何解析NFC標簽,當標簽調度系統檢測到NDEC message所要做的特殊工作,NFC標簽來著不同類型的技術,寫入標簽有不同的方式,Android推薦使用NDEF標准,它是由NFC社區發起的
NDEF data is encapsulated inside a message (NdefMessage) that contains one or more records (NdefRecord). Each NDEF record must be well-formed according to the specification of the type of record that you want to create. Android
also supports other types of tags that do not contain NDEF data, which you can work with by using the classes in the android.nfc.tech package. To learn more about these technologies, see the Advanced NFC topic. Working with these other types of tags involves
writing your own protocol stack to communicate with the tags, so we recommend using NDEF when possible for ease of development and maximum support for Android-powered devices.
NDEF數據封裝在一個由多個NdefRecord組成的NdefMessage中,每一個NDEF記錄必須是格式良好的根據你要創建的具體類型,Android也支持其他不包含NDEF數據的類型,你能夠使用android.nfc.tech進行工作,為了學習這些技術,請看Advanced NFC topic,操作這些標簽會牽涉到你自己的協議棧和標簽進行交流,因此為了簡化開發和最大化支持android設備,我們建議使用NDEF盡可能。
Note: To download complete NDEF specifications, go to the NFC Forum Specification Download site and see Creating common types of NDEF records for examples of how to construct NDEF records.
注意:為了下載完整的NDEF詳情,去NFC社區下載然後閱讀如何構建公共類型的NDEF記錄的例子。
Now that you have some background in NFC tags, the following sections describe in more detail how Android handles NDEF formatted tags. When an Android-powered device scans an NFC tag containing NDEF formatted data, it parses
the message and tries to figure out the data's MIME type or identifying URI. To do this, the system reads the first NdefRecord inside the NdefMessage to determine how to interpret the entire NDEF message (an NDEF message can have multiple NDEF records). In
a well-formed NDEF message, the first NdefRecord contains the following fields:
現在你要具有NFC標簽的背景,如下部分描述如何如何處理NDEF格式標簽的更多詳情。當一個android支持的設別檢測到NFC包含NDEF格式的標簽後,解析裡面的信息然後試圖計算數據的MIME類型和URI身份,為了讀取它,系統閱讀NDEF信息的第一個記錄然後說明整個NDEF信息(一個NDEF信息有多個NDEF記錄),在一個格式良好的NDEF信息內,第一個NdefRecord包含如下字段:
3-bit TNF (Type Name Format)
Indicates how to interpret the variable length type field. Valid values are described in described in Table 1.
指明了如何解析可變長度字段,有效值被描述在表1.
Variable length type
Describes the type of the record. If using TNF_WELL_KNOWN, use this field to specify the Record Type Definition (RTD). Valid RTD values are described in Table 2.
詳細record的類型,如有使用了TNF_WELL_KNOWN,使用這個字段具體得記錄的類型,有效的RTD值被描述在表2。
Variable length ID
A unique identifier for the record. This field is not used often, but if you need to uniquely identify a tag, you can create an ID for it.
record唯一的身份,這個字段不是經常使用的,除非你需要唯一確定一個標簽,你可以為它創建一個ID
Variable length payload
The actual data payload that you want to read or write. An NDEF message can contain multiple NDEF records, so don't assume the full payload is in the first NDEF record of the NDEF message.
確切的你將要讀寫的數據的payload,一個DNEF message能包含大量的 NDEF records,所以不要假定所有的payload在NDEF message的第一個NDEF record。
The tag dispatch system uses the TNF and type fields to try to map a MIME type or URI to the NDEF message. If successful, it encapsulates that information inside of a ACTION_NDEF_DISCOVERED intent along with the actual payload.
However, there are cases when the tag dispatch system cannot determine the type of data based on the first NDEF record. This happens when the NDEF data cannot be mapped to a MIME type or URI, or when the NFC tag does not contain NDEF data to begin with. In
such cases, a Tag object that has information about the tag's technologies and the payload are encapsulated inside of a ACTION_TECH_DISCOVERED intent instead.
標簽調度系統使用TNF和type字段嘗試映射一個MIME類型或者URI到一個NDEF message。如果成功,它將封裝信息進一個ACTION_NDEF_DISCOVERED的intent伴隨了確切的payload,這兒關心當調度系統不能決定數據的類型根據第一個NDEF record,這個情況發生在當NDEF data不能映射到一個MIME類型或者一個URI或者當NFC標簽不包含NDEF的頭信息時,這些情況,一個標簽對象的的信息技術和負載將由ACTION_TECH_DISCOVERED的intent取代
Table 1. describes how the tag dispatch system maps TNF and type fields to MIME types or URIs. It also describes which TNFs cannot be mapped to a MIME type or URI. In these cases, the tag dispatch system falls back to ACTION_TECH_DISCOVERED.
表1:描述標簽調度系統映射TNF and type field到一個MIME類型或者URIs。它也描述了TNFs不能被映射的MIME類型和 URI,如果這樣的話,標簽調度系統將回落給ACTION_TECH_DISCOVERED
For example, if the tag dispatch system encounters a record of type TNF_ABSOLUTE_URI, it maps the variable length type field of that record into a URI. The tag dispatch system encapsulates that URI in the data field of an ACTION_NDEF_DISCOVERED intent along with other information about the tag, such as the payload. On the other hand, if it encounters a record of type TNF_UNKNOWN, it creates an intent that encapsulates the tag's technologies instead.
例如:如果標簽 調度系統檢測到一個TNF_ABSOLUTE_URI類型的記錄,它映射記錄的the variable length type field到一個URI,標簽調度系統封裝URI數據和相應payload的到ACTION_NDEF_DISCOVEREDintent,另一個方面,如果遇到一個TNF_UNKNOWN的記錄,它將創建一個tag's technologies 封裝取代(ACTION_TECH_DISCOVERED)。
TNF_ABSOLUTE_URI
URI based on the type field.
TNF_EMPTY
Falls back to ACTION_TECH_DISCOVERED
.
TNF_EXTERNAL_TYPE
URI based on the URN in the type field. The URN is encoded into the NDEF type field in a shortened form: :
. Android maps
this to a URI in the form: vnd.android.nfc://ext/:
.
TNF_MIME_MEDIA
MIME type based on the type field.
TNF_UNCHANGED
Invalid in the first record, so falls back to ACTION_TECH_DISCOVERED
.
TNF_UNKNOWN
Falls back to ACTION_TECH_DISCOVERED
.
TNF_WELL_KNOWN
MIME type or URI depending on the Record Type Definition (RTD), which you set in the type field. See Table
2. for more information on available RTDs and their mappings.
RTD_ALTERNATIVE_CARRIER
Falls back to ACTION_TECH_DISCOVERED
.
RTD_HANDOVER_CARRIER
Falls back to ACTION_TECH_DISCOVERED
.
RTD_HANDOVER_REQUEST
Falls back to ACTION_TECH_DISCOVERED
.
RTD_HANDOVER_SELECT
Falls back to ACTION_TECH_DISCOVERED
.
RTD_SMART_POSTER
URI based on parsing the payload.
RTD_TEXT
MIME type of text/plain
.
RTD_URI
URI based on payload.
How NFC Tags are Dispatched to Applications
When the tag dispatch system is done creating an intent that encapsulates the NFC tag and its identifying information, it sends the intent to an interested application that filters for the intent. If more than one application
can handle the intent, the Activity Chooser is presented so the user can select the Activity. The tag dispatch system defines three intents, which are listed in order of highest to lowest priority:
當標簽調度系統完成創建一個封裝了NFC標簽和它的身份信息的Intent後,它將發送由過濾器過濾後的intent到對應的應用,如果一個intent有多個應用可以處理,用戶根據Activity Chooser選擇器選擇啟動的Activity,標簽調度系統定義了三種intent類型,優先級由高到低。
Requesting NFC Access in the Android Manifest<喎?/kf/ware/vc/" target="_blank" class="keylink">vc3Ryb25nPjxicj4KPC9wPgo8cD5CZWZvcmUgeW91IGNhbiBhY2Nlc3MgYSBkZXZpY2U="s NFC hardware and properly handle NFC intents, declare these items in your AndroidManifest.xml file:
The NFC
api只包含有限的標簽,需要通過ACTION_TAG_DISCOVERED調度,僅僅給了訪問NDEF messages通過EXTRA_NDEF_MESSAGES 的extra,沒有其他標簽屬性和I/O操作是可用的。api10包含了全部的讀/寫操作支持和前台NDEF推送 ,api14包含了更簡單的方式推送NDEF信息到其他的設備通過Android Beam和額外創建NDEF records便利的方法。
聲明該屬性後Google Play將顯示你的應用必須支持NFC設備:
If your application uses NFC functionality, but that functionality is not crucial to your application, you can omit the uses-feature element and check for NFC avalailbility at runtime by checking to see if getDefaultAdapter() is null.
如果你的應用中的NFC功能不是主要的功能,可以忽略uses-feature元素,然後在代碼中通過getDefaultAdapter()是否為null動態檢測NFC的可用性。
Filtering for NFC Intents
Because NFC tag deployments vary and are many times not under your control, this is not always possible, which
is why you can fallback to the other two intents when necessary. When you have control over the types of tags and data written, it is recommended that you use NDEF to format your tags. The following sections describe how to filter for each type of intent.
因為NFC標簽部署變化的和很多時候不在你的控制之下,這個部署並不總是可用的所以你可以在必要時回調其他兩種標簽,當你擁有了以上幾種類型標簽的寫操作時,建議使用NDEF格式化你的標簽,以下部分描述如何過濾每種類型的intent
ACTION_NDEF_DISCOVERED:
To filter for ACTION_NDEF_DISCOVERED intents, declare the intent filter along with the type of data that you
want to filter for. The following example filters for ACTION_NDEF_DISCOVERED intents with a MIME type of text/plain:
過濾ACTION_NDEF_DISCOVERED的intent,使用你想要過濾的數據類型的intent filter,如下使用text/plain類型的MIME進行過濾的ACTION_NDEF_DISCOVERED的intent:
The following example filters for a URI in the form of http://developer.android.com/index.html
If your activity filters for the ACTION_TECH_DISCOVERED intent, you must create an XML resource file that specifies
the technologies that your activity supports within a tech-list set. Your activity is considered a match if a tech-list set is a subset of the technologies that are supported by the tag, which you can obtain by calling getTechList().
如果你的Activity過濾ACTION_TECH_DISCOVERED的intent,你必須創建一個包含具體的支持的技術的tech-list的XML資源文件,你的Activity如果匹配了tech-list其中一個子集代表是匹配的。
The following sample defines all of the technologies.
You can remove the ones that you do not need. Save this file (you can name it anything you wish) in the
如下例子定義了所有的技術,你可以移除你不需要的那些,保存這個文件在/res/xml文件夾下
You can also specify multiple tech-list sets. Each of the tech-list sets is considered independently, and your activity is considered a match if any single tech-list set is a subset of the technologies that are returned by getTechList(). This provides AND and OR semantics for matching technologies. The following example matches tags that can support the NfcA and Ndef technologies or can support the NfcB and Ndef technologies:android.nfc.tech.IsoDep android.nfc.tech.NfcA android.nfc.tech.NfcB android.nfc.tech.NfcF android.nfc.tech.NfcV android.nfc.tech.Ndef android.nfc.tech.NdefFormatable android.nfc.tech.MifareClassic android.nfc.tech.MifareUltralight
也可以指定多個 tech-list集合,每個 tech-list都是獨立的,你的Activity只有在任何單一一個 通過getTechList()返回的tech-list的子集時才被認為時匹配的。兩個文件是之間是AND關系,文件之內是OR關系。
android.nfc.tech.NfcA android.nfc.tech.Ndef
In your AndroidManifest.xml file, specify the resource file that you just created in theandroid.nfc.tech.NfcB android.nfc.tech.Ndef
...For more information about working with tag technologies and the ACTION_TECH_DISCOVERED intent, see Working with Supported Tag Technologies in the Advanced NFC document....
To filter for ACTION_TAG_DISCOVERED use the following intent filter:
Obtaining information from intents
If an activity starts because of an NFC intent, you can obtain information about the scanned NFC tag from the intent. Intents can contain the following extras depending on the tag that was scanned:
如果由於一個NFC的Intent啟動的Activity,你可以通過從被掃描到的intent獲取信息,被掃描的intent可以包含如下extras:
EXTRA_TAG (required):
A Tag object representing the scanned tag.
EXTRA_NDEF_MESSAGES (optional): An array of NDEF messages parsed from the tag. This extra is mandatory on intents.
{@link android.nfc.NfcAdapter#EXTRA_ID (optional): The low-level ID of the tag.
To obtain these extras, check to see if your activity was launched with one of the NFC intents to ensure that a tag was scanned, and then obtain the extras out of the intent. The following example checks for the ACTION_NDEF_DISCOVERED intent and gets the NDEF messages from an intent extra.
為了獲取這些extras,檢測你的Activity通過一個NFC
intent被發起以確保一個標簽被掃描到,然後從intent獲取extras,如下例子檢測ACTION_NDEF_DISCOVERED的intent然後從intent extra中獲取NDEF messages。
public void onResume() { super.onResume(); ... if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(getIntent().getAction())) { Parcelable[] rawMsgs = intent.getParcelableArrayExtra(NfcAdapter.EXTRA_NDEF_MESSAGES); if (rawMsgs != null) { msgs = new NdefMessage[rawMsgs.length]; for (int i = 0; i < rawMsgs.length; i++) { msgs[i] = (NdefMessage) rawMsgs[i]; } } } //process the msgs array }Alternatively, you can obtain a Tag object from the intent, which will contain the payload and allow you to enumerate the tag's technologies:
另外,你可以獲取一個標簽對象,並從標簽對象上可以獲取payload並且允許你枚舉出所有的tag's technologies
Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
This section describes
how to create common types of NDEF records to help you when writing to NFC tags or sending data with Android Beam. Starting with Android 4.0 (API level 14), the createUri() method is available to help you create URI records automatically. Starting in Android
4.1 (API level 16), createExternal() and createMime() are available to help you create MIME and external type NDEF records. Use these helper methods whenever possible to avoid mistakes when manually creating NDEF records.
這部分描述了創建公共的NDEF records當你需要寫標簽或發送數據到給一個Android Beam,從Android 4.0 (API level 14)起createUri()是可用的幫助你自動創建URI
records,從Android 4.1 (API level 16)起createExternal() and createMime()是可用的幫助你創建MIME and external type NDEF records,使用幫助方法盡可能來避免因為手動創建NDEF records時出現錯誤
This
section also describes how to create the corresponding intent filter for the record. All of these NDEF record examples should be in the first NDEF record of the NDEF message that you are writing to a tag or beaming.
這部分描述了如何創建對應 intent filter對應的record,所有這些NDEF record 例子都應該在你寫標簽或者beaming的NDEF message的第一個NDEF record
TNF_ABSOLUTE_URI:
Note: We recommend that you use the RTD_URI type instead of TNF_ABSOLUTE_URI, because it is more efficient.
建議使用RTD_URI替代TNF_ABSOLUTE_URI
You
can create a TNF_ABSOLUTE_URI NDEF record in the following way:
NdefRecord uriRecord = new NdefRecord( NdefRecord.TNF_ABSOLUTE_URI , "http://developer.android.com/index.html".getBytes(Charset.forName("US-ASCII")), new byte[0], new byte[0]);The intent filter for the previous NDEF record would look like this:
You
can create a TNF_MIME_MEDIA NDEF record in the following ways.
Using
the createMime() method:
NdefRecord mimeRecord = NdefRecord.createMime("application/vnd.com.example.android.beam", "Beam me up, Android".getBytes(Charset.forName("US-ASCII")));Creating the NdefRecord manually:
NdefRecord mimeRecord = new NdefRecord( NdefRecord.TNF_MIME_MEDIA , "application/vnd.com.example.android.beam".getBytes(Charset.forName("US-ASCII")), new byte[0], "Beam me up, Android!".getBytes(Charset.forName("US-ASCII")));The intent filter for the previous NDEF records would look like this:
You
can create a TNF_WELL_KNOWN NDEF record in the following way:
public NdefRecord createTextRecord(String payload, Locale locale, boolean encodeInUtf8) { byte[] langBytes = locale.getLanguage().getBytes(Charset.forName("US-ASCII")); Charset utfEncoding = encodeInUtf8 ? Charset.forName("UTF-8") : Charset.forName("UTF-16"); byte[] textBytes = payload.getBytes(utfEncoding); int utfBit = encodeInUtf8 ? 0 : (1 << 7); char status = (char) (utfBit + langBytes.length); byte[] data = new byte[1 + langBytes.length + textBytes.length]; data[0] = (byte) status; System.arraycopy(langBytes, 0, data, 1, langBytes.length); System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_TEXT, new byte[0], data); return record; }the intent filter would look like this:
You
can create a TNF_WELL_KNOWN NDEF record in the following ways.
Using
the createUri(String) method:
NdefRecord rtdUriRecord1 = NdefRecord.createUri("http://example.com");Using the createUri(Uri) method:
Uri uri = new Uri("http://example.com"); NdefRecord rtdUriRecord2 = NdefRecord.createUri(uri);Creating the NdefRecord manually:
byte[] uriField = "example.com".getBytes(Charset.forName("US-ASCII")); byte[] payload = new byte[uriField.length + 1]; //add 1 for the URI Prefix byte payload[0] = 0x01; //prefixes http://www. to the URI System.arraycopy(uriField, 0, payload, 1, uriField.length); //appends URI to payload NdefRecord rtdUriRecord = new NdefRecord( NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], payload);The intent filter for the previous NDEF records would look like this:
You can create a TNF_EXTERNAL_TYPE NDEF record in the following ways:
Using the createExternal() method:
byte[] payload; //assign to your data String domain = "com.example"; //usually your app's package name String type = "externalType"; NdefRecord extRecord = NdefRecord.createExternal(domain, type, payload);Creating the NdefRecord manually:
byte[] payload; ... NdefRecord extRecord = new NdefRecord( NdefRecord.TNF_EXTERNAL_TYPE, "com.example:externalType", new byte[0], payload);The intent filter for the previous NDEF records would look like this:
Use TNF_EXTERNAL_TYPE for more generic NFC tag deployments to better support both Android-powered and non-Android-powered devices.
Note: URNs for TNF_EXTERNAL_TYPE have a canonical format of: urn:nfc:ext:example.com:externalType, however the NFC Forum RTD specification declares that the urn:nfc:ext: portion of the URN must be ommitted from the NDEF record. So all you need to provide is the domain (example.com in the example) and type (externalType in the example) separated by a colon. When dispatching TNF_EXTERNAL_TYPE, Android converts the urn:nfc:ext:example.com:externalType URN to a vnd.android.nfc://ext/example.com:externalType URI, which is what the intent filter in the example declares.
Android Application Records
Introduced in Android 4.0 (API level 14), an Android Application Record (AAR) provides a stronger certainty that your application is started when an NFC tag is scanned. An AAR has the package name of an application embedded inside an NDEF record. You can add an AAR to any NDEF record of your NDEF message, because Android searches the entire NDEF message for AARs. If it finds an AAR, it starts the application based on the package name inside the AAR. If the application is not present on the device, Google Play is launched to download the application.
Android 4.0 (API level 14)引進的,一個Android Application Record (AAR)提供了更強的功能,當你的NFC標簽被掃描會啟動你的應用,一個AAR由一個應用的包名被嵌入在NDEF record。你能增加一個AAR到NDEF裡任何一個NDEF record因為Android搜索全部NDEF message中的AAR,如果找到了AAR,它就啟動AAR中包名對應的應用,如果應用不存在你的設備中,Google Play會被發起來下載對應的應用。
AARs are useful if you want to prevent other applications from filtering for the same intent and potentially handling specific tags that you have deployed. AARs are only supported at the application level, because of the package name constraint, and not at the Activity level as with intent filtering. If you want to handle an intent at the Activity level, use intent filters.
AAR是有用的對於你想防止其他應用過濾相同的intent,和其他應用處理你部署的具體的標簽,因為AARs僅僅支持應用水平(由包名常量指定),不能被過濾由其他的應用通過intent filtering,如果你想處理一個intent在Activity水平,使用intent filters。
If a tag contains an AAR, the tag dispatch system dispatches in the following manner:
如果一個標簽包含一個AAR,標簽調度系統采用如下方式進行調度:
1.Try to start an Activity using an intent filter as normal. If the Activity that matches the intent also matches the AAR, start the Activity.
試圖使用intent filter啟動一個Activity正常情況下,如果由intent匹配的Activity也匹配AAR,啟動Activity
2.If
the Activity that filters for the intent does not match the AAR, if multiple Activities can handle the intent, or if no Activity handles the intent, start the application specified by the AAR.
如果filter過濾的intent對應的Activity不匹配AAR,如果多個Activity能處理intent,或者沒有應用能處理intent,啟動由AAR具體指定的應用
3.If
no application can start with the AAR, go to Google Play to download the application based on the AAR.
如果沒有AAR所指定的應用,將打開Google Play下載AAR指定的應用
Android provides a simple API to create an AAR, createApplicationRecord(). All you need to do is embed the AAR anywhere in your NdefMessage. You do not want to use the first record of your NdefMessage, unless the AAR is the only
record in the NdefMessage. This is because the Android system checks the first record of an NdefMessage to determine the MIME type or URI of the tag, which is used to create an intent for applications to filter. The following code shows you how to create an
AAR:
android提供了一個簡單的api,createApplicationRecord()創建AAR,你需要嵌入AAR在任何NdefMessage,你應該使用NdefMessage中的第一個record,除非NdefMessage只有一個record,因為android系統檢查NdefMessage第一個record決定標簽的MIME類型或者URI,那用來創建一個intent為應用來過濾,下面代碼教你如何創建一個AAR:
NdefMessage msg = new NdefMessage( new NdefRecord[] { ..., NdefRecord.createApplicationRecord("com.example.android.beam")}
前面一篇文章,分析了AppWidgetProvider和RemoteView的源碼,從中我們可以知道它們的實現原理,AppWidgetProvider是一個Broadca
Android 中使用ExpandableListView 實現分組一個視圖顯示垂直滾動兩級列表中的條目。這不同於列表視圖,允許兩個層次,類似於QQ的好友分組
1 概述在前面的《路徑和文字》中,講解了path的基本用法,這裡講解一些上篇沒有講到的東西。2 Path 這裡講解path相關的方法,後面繼續講解PathMeasure,
Android的消息機制幾乎是面試必問的話題,當然也並不是因為面試,而去學習,更重要的是它在Android的開發中是必不可少的,占著舉足輕重的地位,所以弄懂它是很有必要的