├── .gitignore ├── LICENSE ├── README.md ├── build.gradle ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── nfc-app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── com │ │ └── example │ │ └── nfc │ │ ├── MainActivity.java │ │ ├── UriPrefix.java │ │ ├── base │ │ └── BaseNfcActivity.java │ │ └── ui │ │ ├── ReadMUActivity.java │ │ ├── ReadTextActivity.java │ │ ├── ReadUriActivity.java │ │ ├── RunAppActivity.java │ │ ├── RunUrlActivity.java │ │ ├── WriteMUActivity.java │ │ ├── WriteTextActivity.java │ │ └── WriteUriActivity.java │ └── res │ ├── drawable │ ├── nfc_read.png │ ├── nfc_run.png │ └── nfc_write.png │ ├── layout │ ├── activity_main.xml │ ├── activity_read_mu.xml │ ├── activity_read_text.xml │ ├── activity_read_uri.xml │ ├── activity_run_app.xml │ ├── activity_run_url.xml │ ├── activity_write_mu.xml │ ├── activity_write_text.xml │ └── activity_write_uri.xml │ ├── mipmap-hdpi │ └── ic_launcher.png │ ├── mipmap-mdpi │ └── ic_launcher.png │ ├── mipmap-xhdpi │ └── ic_launcher.png │ ├── mipmap-xxhdpi │ └── ic_launcher.png │ ├── mipmap-xxxhdpi │ └── ic_launcher.png │ ├── values-w820dp │ └── dimens.xml │ └── values │ ├── colors.xml │ ├── dimens.xml │ ├── strings.xml │ └── styles.xml ├── settings.gradle └── website └── static └── screenshot.jpg /.gitignore: -------------------------------------------------------------------------------- 1 | # built application files 2 | *.apk 3 | *.ap_ 4 | 5 | # files for the dex VM 6 | *.dex 7 | 8 | # Java class files 9 | *.class 10 | 11 | # generated files 12 | bin/ 13 | gen/ 14 | out/ 15 | 16 | # gradle files 17 | .gradle/ 18 | build/ 19 | 20 | # Local configuration file (sdk path, etc) 21 | local.properties 22 | 23 | # Eclipse project files 24 | .classpath 25 | .project 26 | 27 | # Proguard folder generated by Eclipse 28 | proguard/ 29 | 30 | # log files 31 | *.log 32 | 33 | # Android Studio Navigation editor temp files 34 | .navigation/ 35 | 36 | # Android Studio captures folder 37 | captures/ 38 | 39 | # Intellij project files 40 | *.iml 41 | *.ipr 42 | *.iws 43 | .idea/ 44 | 45 | # keystore files 46 | *.jks 47 | 48 | # External native build folder generated in Android Studio 2.2 and later 49 | .externalNativeBuild 50 | 51 | # Google Services (e.g. APIs or Firebase) 52 | google-services.json 53 | 54 | # Freeline 55 | freeline.py 56 | freeline/ 57 | freeline_project_description.json 58 | 59 | .DS_Store 60 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy 4 | of this software and associated documentation files (the "Software"), to deal 5 | in the Software without restriction, including without limitation the rights 6 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 7 | copies of the Software, and to permit persons to whom the Software is 8 | furnished to do so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Android-NFC 2 | 3 | NFC(Near Field Communication,近场通信)是一种数据传输技术。与Wi-Fi、蓝牙、红外线等数据传输技术的一个主要差异就是有效距离一般不能超过4厘米。但是NFC传输速度要比红外快。目前NFC已经出现了一些应用,例如电子标签识别、刷手机、点对点付款、身份识别、信息记录等. 4 | 5 | # Android对NFC的支持 6 | 7 | 不同的NFC标签之间差异很大,有的只支持简单的读写操作,有时还会采用支持一次性写入的芯片,将NFC标签设计成只读的。当然,也存在一些复杂的NFC标签,例如,有一些NFC标签可以通过硬件加密的方式限制对某一区域的访问。还有一些标签自带操作环境,允许NFC设备与这些标签进行更复杂的交互。这些标签中的数据也会采用不同的格式。但Android SDK API主要支持NFC论坛标准(Forum Standard),这种标准被称为NDEF(NFC Data Exchange Format,NFC数据交换格式)。 8 | 9 | # Preview 10 | 11 | ![](https://raw.githubusercontent.com/smartbetter/android-nfc/master/website/static/screenshot.jpg) 12 | -------------------------------------------------------------------------------- /build.gradle: -------------------------------------------------------------------------------- 1 | // Top-level build file where you can add configuration options common to all sub-projects/modules. 2 | 3 | buildscript { 4 | repositories { 5 | jcenter() 6 | } 7 | dependencies { 8 | classpath 'com.android.tools.build:gradle:2.3.3' 9 | 10 | // NOTE: Do not place your application dependencies here; they belong 11 | // in the individual module build.gradle files 12 | } 13 | } 14 | 15 | allprojects { 16 | repositories { 17 | jcenter() 18 | } 19 | } 20 | 21 | task clean(type: Delete) { 22 | delete rootProject.buildDir 23 | } 24 | -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | 3 | # IDE (e.g. Android Studio) users: 4 | # Gradle settings configured through the IDE *will override* 5 | # any settings specified in this file. 6 | 7 | # For more details on how to configure your build environment visit 8 | # http://www.gradle.org/docs/current/userguide/build_environment.html 9 | 10 | # Specifies the JVM arguments used for the daemon process. 11 | # The setting is particularly useful for tweaking memory settings. 12 | org.gradle.jvmargs=-Xmx1536m 13 | 14 | # When configured, Gradle will run in incubating parallel mode. 15 | # This option should only be used with decoupled projects. More details, visit 16 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 17 | # org.gradle.parallel=true 18 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Mar 13 10:32:12 CST 2017 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-3.3-all.zip 7 | -------------------------------------------------------------------------------- /gradlew: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | ############################################################################## 4 | ## 5 | ## Gradle start up script for UN*X 6 | ## 7 | ############################################################################## 8 | 9 | # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 10 | DEFAULT_JVM_OPTS="" 11 | 12 | APP_NAME="Gradle" 13 | APP_BASE_NAME=`basename "$0"` 14 | 15 | # Use the maximum available, or set MAX_FD != -1 to use that value. 16 | MAX_FD="maximum" 17 | 18 | warn ( ) { 19 | echo "$*" 20 | } 21 | 22 | die ( ) { 23 | echo 24 | echo "$*" 25 | echo 26 | exit 1 27 | } 28 | 29 | # OS specific support (must be 'true' or 'false'). 30 | cygwin=false 31 | msys=false 32 | darwin=false 33 | case "`uname`" in 34 | CYGWIN* ) 35 | cygwin=true 36 | ;; 37 | Darwin* ) 38 | darwin=true 39 | ;; 40 | MINGW* ) 41 | msys=true 42 | ;; 43 | esac 44 | 45 | # Attempt to set APP_HOME 46 | # Resolve links: $0 may be a link 47 | PRG="$0" 48 | # Need this for relative symlinks. 49 | while [ -h "$PRG" ] ; do 50 | ls=`ls -ld "$PRG"` 51 | link=`expr "$ls" : '.*-> \(.*\)$'` 52 | if expr "$link" : '/.*' > /dev/null; then 53 | PRG="$link" 54 | else 55 | PRG=`dirname "$PRG"`"/$link" 56 | fi 57 | done 58 | SAVED="`pwd`" 59 | cd "`dirname \"$PRG\"`/" >/dev/null 60 | APP_HOME="`pwd -P`" 61 | cd "$SAVED" >/dev/null 62 | 63 | CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar 64 | 65 | # Determine the Java command to use to start the JVM. 66 | if [ -n "$JAVA_HOME" ] ; then 67 | if [ -x "$JAVA_HOME/jre/sh/java" ] ; then 68 | # IBM's JDK on AIX uses strange locations for the executables 69 | JAVACMD="$JAVA_HOME/jre/sh/java" 70 | else 71 | JAVACMD="$JAVA_HOME/bin/java" 72 | fi 73 | if [ ! -x "$JAVACMD" ] ; then 74 | die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME 75 | 76 | Please set the JAVA_HOME variable in your environment to match the 77 | location of your Java installation." 78 | fi 79 | else 80 | JAVACMD="java" 81 | which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 82 | 83 | Please set the JAVA_HOME variable in your environment to match the 84 | location of your Java installation." 85 | fi 86 | 87 | # Increase the maximum file descriptors if we can. 88 | if [ "$cygwin" = "false" -a "$darwin" = "false" ] ; then 89 | MAX_FD_LIMIT=`ulimit -H -n` 90 | if [ $? -eq 0 ] ; then 91 | if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then 92 | MAX_FD="$MAX_FD_LIMIT" 93 | fi 94 | ulimit -n $MAX_FD 95 | if [ $? -ne 0 ] ; then 96 | warn "Could not set maximum file descriptor limit: $MAX_FD" 97 | fi 98 | else 99 | warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT" 100 | fi 101 | fi 102 | 103 | # For Darwin, add options to specify how the application appears in the dock 104 | if $darwin; then 105 | GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\"" 106 | fi 107 | 108 | # For Cygwin, switch paths to Windows format before running java 109 | if $cygwin ; then 110 | APP_HOME=`cygpath --path --mixed "$APP_HOME"` 111 | CLASSPATH=`cygpath --path --mixed "$CLASSPATH"` 112 | JAVACMD=`cygpath --unix "$JAVACMD"` 113 | 114 | # We build the pattern for arguments to be converted via cygpath 115 | ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null` 116 | SEP="" 117 | for dir in $ROOTDIRSRAW ; do 118 | ROOTDIRS="$ROOTDIRS$SEP$dir" 119 | SEP="|" 120 | done 121 | OURCYGPATTERN="(^($ROOTDIRS))" 122 | # Add a user-defined pattern to the cygpath arguments 123 | if [ "$GRADLE_CYGPATTERN" != "" ] ; then 124 | OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)" 125 | fi 126 | # Now convert the arguments - kludge to limit ourselves to /bin/sh 127 | i=0 128 | for arg in "$@" ; do 129 | CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -` 130 | CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option 131 | 132 | if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition 133 | eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"` 134 | else 135 | eval `echo args$i`="\"$arg\"" 136 | fi 137 | i=$((i+1)) 138 | done 139 | case $i in 140 | (0) set -- ;; 141 | (1) set -- "$args0" ;; 142 | (2) set -- "$args0" "$args1" ;; 143 | (3) set -- "$args0" "$args1" "$args2" ;; 144 | (4) set -- "$args0" "$args1" "$args2" "$args3" ;; 145 | (5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;; 146 | (6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;; 147 | (7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;; 148 | (8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;; 149 | (9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;; 150 | esac 151 | fi 152 | 153 | # Split up the JVM_OPTS And GRADLE_OPTS values into an array, following the shell quoting and substitution rules 154 | function splitJvmOpts() { 155 | JVM_OPTS=("$@") 156 | } 157 | eval splitJvmOpts $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS 158 | JVM_OPTS[${#JVM_OPTS[*]}]="-Dorg.gradle.appname=$APP_BASE_NAME" 159 | 160 | exec "$JAVACMD" "${JVM_OPTS[@]}" -classpath "$CLASSPATH" org.gradle.wrapper.GradleWrapperMain "$@" 161 | -------------------------------------------------------------------------------- /gradlew.bat: -------------------------------------------------------------------------------- 1 | @if "%DEBUG%" == "" @echo off 2 | @rem ########################################################################## 3 | @rem 4 | @rem Gradle startup script for Windows 5 | @rem 6 | @rem ########################################################################## 7 | 8 | @rem Set local scope for the variables with windows NT shell 9 | if "%OS%"=="Windows_NT" setlocal 10 | 11 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. 12 | set DEFAULT_JVM_OPTS= 13 | 14 | set DIRNAME=%~dp0 15 | if "%DIRNAME%" == "" set DIRNAME=. 16 | set APP_BASE_NAME=%~n0 17 | set APP_HOME=%DIRNAME% 18 | 19 | @rem Find java.exe 20 | if defined JAVA_HOME goto findJavaFromJavaHome 21 | 22 | set JAVA_EXE=java.exe 23 | %JAVA_EXE% -version >NUL 2>&1 24 | if "%ERRORLEVEL%" == "0" goto init 25 | 26 | echo. 27 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 28 | echo. 29 | echo Please set the JAVA_HOME variable in your environment to match the 30 | echo location of your Java installation. 31 | 32 | goto fail 33 | 34 | :findJavaFromJavaHome 35 | set JAVA_HOME=%JAVA_HOME:"=% 36 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe 37 | 38 | if exist "%JAVA_EXE%" goto init 39 | 40 | echo. 41 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 42 | echo. 43 | echo Please set the JAVA_HOME variable in your environment to match the 44 | echo location of your Java installation. 45 | 46 | goto fail 47 | 48 | :init 49 | @rem Get command-line arguments, handling Windowz variants 50 | 51 | if not "%OS%" == "Windows_NT" goto win9xME_args 52 | if "%@eval[2+2]" == "4" goto 4NT_args 53 | 54 | :win9xME_args 55 | @rem Slurp the command line arguments. 56 | set CMD_LINE_ARGS= 57 | set _SKIP=2 58 | 59 | :win9xME_args_slurp 60 | if "x%~1" == "x" goto execute 61 | 62 | set CMD_LINE_ARGS=%* 63 | goto execute 64 | 65 | :4NT_args 66 | @rem Get arguments from the 4NT Shell from JP Software 67 | set CMD_LINE_ARGS=%$ 68 | 69 | :execute 70 | @rem Setup the command line 71 | 72 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar 73 | 74 | @rem Execute Gradle 75 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %CMD_LINE_ARGS% 76 | 77 | :end 78 | @rem End local scope for the variables with windows NT shell 79 | if "%ERRORLEVEL%"=="0" goto mainEnd 80 | 81 | :fail 82 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of 83 | rem the _cmd.exe /c_ return code! 84 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 85 | exit /b 1 86 | 87 | :mainEnd 88 | if "%OS%"=="Windows_NT" endlocal 89 | 90 | :omega 91 | -------------------------------------------------------------------------------- /nfc-app/.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | -------------------------------------------------------------------------------- /nfc-app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | 3 | android { 4 | compileSdkVersion 25 5 | buildToolsVersion "25.0.3" 6 | defaultConfig { 7 | applicationId "com.example.nfc" 8 | minSdkVersion 15 9 | targetSdkVersion 25 10 | versionCode 2 11 | versionName "1.0.1" 12 | } 13 | buildTypes { 14 | release { 15 | minifyEnabled false 16 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 17 | } 18 | } 19 | } 20 | 21 | dependencies { 22 | compile fileTree(dir: 'libs', include: ['*.jar']) 23 | compile 'com.android.support:appcompat-v7:25.3.1' 24 | testCompile 'junit:junit:4.12' 25 | } -------------------------------------------------------------------------------- /nfc-app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # By default, the flags in this file are appended to flags specified 3 | # in C:\Android\sdk/tools/proguard/proguard-android.txt 4 | # You can edit the include path and order by changing the proguardFiles 5 | # directive in build.gradle. 6 | # 7 | # For more details, see 8 | # http://developer.android.com/guide/developing/tools/proguard.html 9 | 10 | # Add any project specific keep options here: 11 | 12 | # If your project uses WebView with JS, uncomment the following 13 | # and specify the fully qualified class name to the JavaScript interface 14 | # class: 15 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 16 | # public *; 17 | #} 18 | -------------------------------------------------------------------------------- /nfc-app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 4 | 5 | 6 | 7 | 8 | 9 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 25 | 28 | 31 | 34 | 37 | 40 | 43 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/MainActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc; 2 | 3 | import android.content.Intent; 4 | import android.os.Bundle; 5 | import android.support.v7.app.AppCompatActivity; 6 | import android.view.View; 7 | import android.widget.AdapterView; 8 | import android.widget.ArrayAdapter; 9 | import android.widget.ListView; 10 | 11 | import com.example.nfc.ui.ReadMUActivity; 12 | import com.example.nfc.ui.ReadTextActivity; 13 | import com.example.nfc.ui.ReadUriActivity; 14 | import com.example.nfc.ui.RunAppActivity; 15 | import com.example.nfc.ui.RunUrlActivity; 16 | import com.example.nfc.ui.WriteMUActivity; 17 | import com.example.nfc.ui.WriteTextActivity; 18 | import com.example.nfc.ui.WriteUriActivity; 19 | 20 | public class MainActivity extends AppCompatActivity { 21 | private static final String[] strs = new String[]{ 22 | "自动运行程序(NDEF格式)", 23 | "自动打开网页(NDEF格式)", 24 | "读NFC标签中的文本数据(NDEF格式)", 25 | "写NFC标签中的文本数据(NDEF格式)", 26 | "读NFC标签中的Uri数据(NDEF格式)", 27 | "写NFC标签中的Uri数据(NDEF格式)", 28 | "读NFC标签非NDEF格式的数据(非NDEF格式)", 29 | "写NFC标签非NDEF格式的数据(非NDEF格式)" 30 | }; 31 | 32 | @Override 33 | public void onCreate(Bundle savedInstanceState) { 34 | super.onCreate(savedInstanceState); 35 | setContentView(R.layout.activity_main); 36 | 37 | ListView listView = (ListView) findViewById(R.id.listview); 38 | listView.setAdapter(new ArrayAdapter(this, android.R.layout.simple_list_item_1, strs)); 39 | listView.setOnItemClickListener(new AdapterView.OnItemClickListener() { 40 | @Override 41 | public void onItemClick(AdapterView parent, View view, int position, long id) { 42 | switchActivity(position); 43 | } 44 | }); 45 | } 46 | 47 | private void switchActivity(int position) { 48 | switch (position) { 49 | case 0: //自动运行程序 50 | startActivity(new Intent(this, RunAppActivity.class)); 51 | break; 52 | case 1: //自动打开网页 53 | startActivity(new Intent(this, RunUrlActivity.class)); 54 | break; 55 | case 2: //读NFC标签中的文本数据 56 | startActivity(new Intent(this, ReadTextActivity.class)); 57 | break; 58 | case 3: //写NFC标签中的文本数据 59 | startActivity(new Intent(this, WriteTextActivity.class)); 60 | break; 61 | case 4: //读NFC标签中的Uri数据 62 | startActivity(new Intent(this, ReadUriActivity.class)); 63 | break; 64 | case 5: //写NFC标签中的Uri数据 65 | startActivity(new Intent(this, WriteUriActivity.class)); 66 | break; 67 | case 6: //读NFC标签非NDEF格式的数据 68 | startActivity(new Intent(this, ReadMUActivity.class)); 69 | break; 70 | case 7: //写NFC标签非NDEF格式的数据 71 | startActivity(new Intent(this, WriteMUActivity.class)); 72 | break; 73 | default: 74 | break; 75 | } 76 | } 77 | } 78 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/UriPrefix.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc; 2 | 3 | import java.util.HashMap; 4 | import java.util.Map; 5 | 6 | public class UriPrefix { 7 | public static final Map URI_PREFIX_MAP = new HashMap<>(); 8 | 9 | // 预先定义已知Uri前缀 10 | static { 11 | URI_PREFIX_MAP.put((byte) 0x00, ""); 12 | URI_PREFIX_MAP.put((byte) 0x01, "http://www."); 13 | URI_PREFIX_MAP.put((byte) 0x02, "https://www."); 14 | URI_PREFIX_MAP.put((byte) 0x03, "http://"); 15 | URI_PREFIX_MAP.put((byte) 0x04, "https://"); 16 | URI_PREFIX_MAP.put((byte) 0x05, "tel:"); 17 | URI_PREFIX_MAP.put((byte) 0x06, "mailto:"); 18 | URI_PREFIX_MAP.put((byte) 0x07, "ftp://anonymous:anonymous@"); 19 | URI_PREFIX_MAP.put((byte) 0x08, "ftp://ftp."); 20 | URI_PREFIX_MAP.put((byte) 0x09, "ftps://"); 21 | URI_PREFIX_MAP.put((byte) 0x0A, "sftp://"); 22 | URI_PREFIX_MAP.put((byte) 0x0B, "smb://"); 23 | URI_PREFIX_MAP.put((byte) 0x0C, "nfs://"); 24 | URI_PREFIX_MAP.put((byte) 0x0D, "ftp://"); 25 | URI_PREFIX_MAP.put((byte) 0x0E, "dav://"); 26 | URI_PREFIX_MAP.put((byte) 0x0F, "news:"); 27 | URI_PREFIX_MAP.put((byte) 0x10, "telnet://"); 28 | URI_PREFIX_MAP.put((byte) 0x11, "imap:"); 29 | URI_PREFIX_MAP.put((byte) 0x12, "rtsp://"); 30 | URI_PREFIX_MAP.put((byte) 0x13, "urn:"); 31 | URI_PREFIX_MAP.put((byte) 0x14, "pop:"); 32 | URI_PREFIX_MAP.put((byte) 0x15, "sip:"); 33 | URI_PREFIX_MAP.put((byte) 0x16, "sips:"); 34 | URI_PREFIX_MAP.put((byte) 0x17, "tftp:"); 35 | URI_PREFIX_MAP.put((byte) 0x18, "btspp://"); 36 | URI_PREFIX_MAP.put((byte) 0x19, "btl2cap://"); 37 | URI_PREFIX_MAP.put((byte) 0x1A, "btgoep://"); 38 | URI_PREFIX_MAP.put((byte) 0x1B, "tcpobex://"); 39 | URI_PREFIX_MAP.put((byte) 0x1C, "irdaobex://"); 40 | URI_PREFIX_MAP.put((byte) 0x1D, "file://"); 41 | URI_PREFIX_MAP.put((byte) 0x1E, "urn:epc:id:"); 42 | URI_PREFIX_MAP.put((byte) 0x1F, "urn:epc:tag:"); 43 | URI_PREFIX_MAP.put((byte) 0x20, "urn:epc:pat:"); 44 | URI_PREFIX_MAP.put((byte) 0x21, "urn:epc:raw:"); 45 | URI_PREFIX_MAP.put((byte) 0x22, "urn:epc:"); 46 | URI_PREFIX_MAP.put((byte) 0x23, "urn:nfc:"); 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/base/BaseNfcActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.base; 2 | 3 | import android.app.PendingIntent; 4 | import android.content.Intent; 5 | import android.nfc.NfcAdapter; 6 | import android.support.v7.app.AppCompatActivity; 7 | 8 | /** 9 | * 1.子类需要在onCreate方法中做Activity初始化。 10 | * 2.子类需要在onNewIntent方法中进行NFC标签相关操作。 11 | * 当launchMode设置为singleTop时,第一次运行调用onCreate方法, 12 | * 第二次运行将不会创建新的Activity实例,将调用onNewIntent方法 13 | * 所以我们获取intent传递过来的Tag数据操作放在onNewIntent方法中执行 14 | * 如果在栈中已经有该Activity的实例,就重用该实例(会调用实例的onNewIntent()) 15 | * 只要NFC标签靠近就执行 16 | */ 17 | public class BaseNfcActivity extends AppCompatActivity { 18 | private NfcAdapter mNfcAdapter; 19 | private PendingIntent mPendingIntent; 20 | 21 | /** 22 | * 启动Activity,界面可见时 23 | */ 24 | @Override 25 | protected void onStart() { 26 | super.onStart(); 27 | mNfcAdapter = NfcAdapter.getDefaultAdapter(this); 28 | //一旦截获NFC消息,就会通过PendingIntent调用窗口 29 | mPendingIntent = PendingIntent.getActivity(this, 0, new Intent(this, getClass()), 0); 30 | } 31 | 32 | /** 33 | * 获得焦点,按钮可以点击 34 | */ 35 | @Override 36 | public void onResume() { 37 | super.onResume(); 38 | //设置处理优于所有其他NFC的处理 39 | if (mNfcAdapter != null) 40 | mNfcAdapter.enableForegroundDispatch(this, mPendingIntent, null, null); 41 | } 42 | 43 | /** 44 | * 暂停Activity,界面获取焦点,按钮可以点击 45 | */ 46 | @Override 47 | public void onPause() { 48 | super.onPause(); 49 | //恢复默认状态 50 | if (mNfcAdapter != null) 51 | mNfcAdapter.disableForegroundDispatch(this); 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/ReadMUActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import java.nio.charset.Charset; 4 | 5 | import android.content.Intent; 6 | import android.nfc.NfcAdapter; 7 | import android.nfc.Tag; 8 | import android.nfc.tech.MifareUltralight; 9 | import android.os.Bundle; 10 | import android.widget.Toast; 11 | 12 | import com.example.nfc.R; 13 | import com.example.nfc.base.BaseNfcActivity; 14 | 15 | public class ReadMUActivity extends BaseNfcActivity { 16 | @Override 17 | public void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_read_mu); 20 | } 21 | 22 | @Override 23 | public void onNewIntent(Intent intent) { 24 | Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 25 | String[] techList = tag.getTechList(); 26 | boolean haveMifareUltralight = false; 27 | for (String tech : techList) { 28 | if (tech.indexOf("MifareUltralight") >= 0) { 29 | haveMifareUltralight = true; 30 | break; 31 | } 32 | } 33 | if (!haveMifareUltralight) { 34 | Toast.makeText(this, "不支持MifareUltralight数据格式", Toast.LENGTH_SHORT).show(); 35 | return; 36 | } 37 | String data = readTag(tag); 38 | if (data != null) 39 | Toast.makeText(this, data, Toast.LENGTH_SHORT).show(); 40 | } 41 | 42 | public String readTag(Tag tag) { 43 | MifareUltralight ultralight = MifareUltralight.get(tag); 44 | try { 45 | ultralight.connect(); 46 | byte[] data = ultralight.readPages(4); 47 | return new String(data, Charset.forName("GB2312")); 48 | } catch (Exception e) { 49 | } finally { 50 | try { 51 | ultralight.close(); 52 | } catch (Exception e) { 53 | } 54 | } 55 | return null; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/ReadTextActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.nfc.NdefMessage; 5 | import android.nfc.NdefRecord; 6 | import android.nfc.NfcAdapter; 7 | import android.nfc.Tag; 8 | import android.nfc.tech.Ndef; 9 | import android.os.Parcelable; 10 | import android.os.Bundle; 11 | import android.widget.TextView; 12 | 13 | import com.example.nfc.R; 14 | import com.example.nfc.base.BaseNfcActivity; 15 | 16 | import java.util.Arrays; 17 | 18 | public class ReadTextActivity extends BaseNfcActivity { 19 | private TextView mNfcText; 20 | private String mTagText; 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_read_text); 26 | mNfcText = (TextView) findViewById(R.id.tv_nfctext); 27 | } 28 | 29 | @Override 30 | public void onNewIntent(Intent intent) { 31 | //1.获取Tag对象 32 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 33 | //2.获取Ndef的实例 34 | Ndef ndef = Ndef.get(detectedTag); 35 | mTagText = ndef.getType() + "\nmaxsize:" + ndef.getMaxSize() + "bytes\n\n"; 36 | readNfcTag(intent); 37 | mNfcText.setText(mTagText); 38 | } 39 | 40 | /** 41 | * 读取NFC标签文本数据 42 | */ 43 | private void readNfcTag(Intent intent) { 44 | if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { 45 | Parcelable[] rawMsgs = intent.getParcelableArrayExtra( 46 | NfcAdapter.EXTRA_NDEF_MESSAGES); 47 | NdefMessage msgs[] = null; 48 | int contentSize = 0; 49 | if (rawMsgs != null) { 50 | msgs = new NdefMessage[rawMsgs.length]; 51 | for (int i = 0; i < rawMsgs.length; i++) { 52 | msgs[i] = (NdefMessage) rawMsgs[i]; 53 | contentSize += msgs[i].toByteArray().length; 54 | } 55 | } 56 | try { 57 | if (msgs != null) { 58 | NdefRecord record = msgs[0].getRecords()[0]; 59 | String textRecord = parseTextRecord(record); 60 | mTagText += textRecord + "\n\ntext\n" + contentSize + " bytes"; 61 | } 62 | } catch (Exception e) { 63 | } 64 | } 65 | } 66 | 67 | /** 68 | * 解析NDEF文本数据,从第三个字节开始,后面的文本数据 69 | * 70 | * @param ndefRecord 71 | * @return 72 | */ 73 | public static String parseTextRecord(NdefRecord ndefRecord) { 74 | /** 75 | * 判断数据是否为NDEF格式 76 | */ 77 | //判断TNF 78 | if (ndefRecord.getTnf() != NdefRecord.TNF_WELL_KNOWN) { 79 | return null; 80 | } 81 | //判断可变的长度的类型 82 | if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_TEXT)) { 83 | return null; 84 | } 85 | try { 86 | //获得字节数组,然后进行分析 87 | byte[] payload = ndefRecord.getPayload(); 88 | //下面开始NDEF文本数据第一个字节,状态字节 89 | //判断文本是基于UTF-8还是UTF-16的,取第一个字节"位与"上16进制的80,16进制的80也就是最高位是1, 90 | //其他位都是0,所以进行"位与"运算后就会保留最高位 91 | String textEncoding = ((payload[0] & 0x80) == 0) ? "UTF-8" : "UTF-16"; 92 | //3f最高两位是0,第六位是1,所以进行"位与"运算后获得第六位 93 | int languageCodeLength = payload[0] & 0x3f; 94 | //下面开始NDEF文本数据第二个字节,语言编码 95 | //获得语言编码 96 | String languageCode = new String(payload, 1, languageCodeLength, "US-ASCII"); 97 | //下面开始NDEF文本数据后面的字节,解析出文本 98 | String textRecord = new String(payload, languageCodeLength + 1, 99 | payload.length - languageCodeLength - 1, textEncoding); 100 | return textRecord; 101 | } catch (Exception e) { 102 | throw new IllegalArgumentException(); 103 | } 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/ReadUriActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.nfc.NdefMessage; 6 | import android.nfc.NdefRecord; 7 | import android.nfc.NfcAdapter; 8 | import android.nfc.Tag; 9 | import android.nfc.tech.Ndef; 10 | import android.os.Bundle; 11 | import android.os.Parcelable; 12 | import android.util.Log; 13 | import android.widget.TextView; 14 | 15 | import com.example.nfc.R; 16 | import com.example.nfc.base.BaseNfcActivity; 17 | import com.example.nfc.UriPrefix; 18 | 19 | import java.nio.charset.Charset; 20 | import java.util.Arrays; 21 | 22 | public class ReadUriActivity extends BaseNfcActivity { 23 | private TextView mNfcText; 24 | private String mTagText; 25 | 26 | @Override 27 | public void onCreate(Bundle savedInstanceState) { 28 | super.onCreate(savedInstanceState); 29 | setContentView(R.layout.activity_read_uri); 30 | mNfcText = (TextView) findViewById(R.id.tv_nfctext); 31 | } 32 | 33 | @Override 34 | public void onNewIntent(Intent intent) { 35 | //获取Tag对象 36 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 37 | //获取Ndef的实例 38 | Ndef ndef = Ndef.get(detectedTag); 39 | mTagText = ndef.getType() + "\n max size:" + ndef.getMaxSize() + " bytes\n\n"; 40 | readNfcTag(intent); 41 | mNfcText.setText(mTagText); 42 | } 43 | 44 | /** 45 | * 读取NFC标签Uri 46 | */ 47 | private void readNfcTag(Intent intent) { 48 | if (NfcAdapter.ACTION_NDEF_DISCOVERED.equals(intent.getAction())) { 49 | Parcelable[] rawMsgs = intent.getParcelableArrayExtra( 50 | NfcAdapter.EXTRA_NDEF_MESSAGES); 51 | NdefMessage ndefMessage = null; 52 | int contentSize = 0; 53 | if (rawMsgs != null) { 54 | if (rawMsgs.length > 0) { 55 | ndefMessage = (NdefMessage) rawMsgs[0]; 56 | contentSize = ndefMessage.toByteArray().length; 57 | } else { 58 | return; 59 | } 60 | } 61 | try { 62 | NdefRecord ndefRecord = ndefMessage.getRecords()[0]; 63 | Log.i("JAVA", ndefRecord.toString()); 64 | Uri uri = parse(ndefRecord); 65 | Log.i("JAVA", "uri:" + uri.toString()); 66 | mTagText += uri.toString() + "\n\nUri\n" + contentSize + " bytes"; 67 | } catch (Exception e) { 68 | } 69 | } 70 | } 71 | 72 | /** 73 | * 解析NdefRecord中Uri数据 74 | * 75 | * @param record 76 | * @return 77 | */ 78 | public static Uri parse(NdefRecord record) { 79 | short tnf = record.getTnf(); 80 | if (tnf == NdefRecord.TNF_WELL_KNOWN) { 81 | return parseWellKnown(record); 82 | } else if (tnf == NdefRecord.TNF_ABSOLUTE_URI) { 83 | return parseAbsolute(record); 84 | } 85 | throw new IllegalArgumentException("Unknown TNF " + tnf); 86 | } 87 | 88 | /** 89 | * 处理绝对的Uri 90 | * 没有Uri识别码,也就是没有Uri前缀,存储的全部是字符串 91 | * 92 | * @param ndefRecord 描述NDEF信息的一个信息段,一个NdefMessage可能包含一个或者多个NdefRecord 93 | * @return 94 | */ 95 | private static Uri parseAbsolute(NdefRecord ndefRecord) { 96 | //获取所有的字节数据 97 | byte[] payload = ndefRecord.getPayload(); 98 | Uri uri = Uri.parse(new String(payload, Charset.forName("UTF-8"))); 99 | return uri; 100 | } 101 | 102 | /** 103 | * 处理已知类型的Uri 104 | * 105 | * @param ndefRecord 106 | * @return 107 | */ 108 | private static Uri parseWellKnown(NdefRecord ndefRecord) { 109 | //判断数据是否是Uri类型的 110 | if (!Arrays.equals(ndefRecord.getType(), NdefRecord.RTD_URI)) 111 | return null; 112 | //获取所有的字节数据 113 | byte[] payload = ndefRecord.getPayload(); 114 | String prefix = UriPrefix.URI_PREFIX_MAP.get(payload[0]); 115 | byte[] prefixBytes = prefix.getBytes(Charset.forName("UTF-8")); 116 | byte[] fullUri = new byte[prefixBytes.length + payload.length - 1]; 117 | System.arraycopy(prefixBytes, 0, fullUri, 0, prefixBytes.length); 118 | System.arraycopy(payload, 1, fullUri, prefixBytes.length, payload.length - 1); 119 | Uri uri = Uri.parse(new String(fullUri, Charset.forName("UTF-8"))); 120 | return uri; 121 | } 122 | } 123 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/RunAppActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.nfc.NdefMessage; 5 | import android.nfc.NdefRecord; 6 | import android.nfc.NfcAdapter; 7 | import android.nfc.Tag; 8 | import android.nfc.tech.Ndef; 9 | import android.nfc.tech.NdefFormatable; 10 | import android.os.Bundle; 11 | import android.widget.Toast; 12 | 13 | import com.example.nfc.R; 14 | import com.example.nfc.base.BaseNfcActivity; 15 | 16 | /** 17 | * 自动运行程序 18 | */ 19 | public class RunAppActivity extends BaseNfcActivity { 20 | private String mPackageName = "com.android.mms";//短信 21 | 22 | @Override 23 | protected void onCreate(Bundle savedInstanceState) { 24 | super.onCreate(savedInstanceState); 25 | setContentView(R.layout.activity_run_app); 26 | } 27 | 28 | @Override 29 | public void onNewIntent(Intent intent) { 30 | if (mPackageName == null) 31 | return; 32 | //1.获取Tag对象 33 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 34 | writeNFCTag(detectedTag); 35 | } 36 | 37 | /** 38 | * 往标签写数据的方法 39 | * 40 | * @param tag 41 | */ 42 | public void writeNFCTag(Tag tag) { 43 | if (tag == null) { 44 | return; 45 | } 46 | NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord 47 | .createApplicationRecord(mPackageName)}); 48 | //转换成字节获得大小 49 | int size = ndefMessage.toByteArray().length; 50 | try { 51 | //2.判断NFC标签的数据类型(通过Ndef.get方法) 52 | Ndef ndef = Ndef.get(tag); 53 | //判断是否为NDEF标签 54 | if (ndef != null) { 55 | ndef.connect(); 56 | //判断是否支持可写 57 | if (!ndef.isWritable()) { 58 | return; 59 | } 60 | //判断标签的容量是否够用 61 | if (ndef.getMaxSize() < size) { 62 | return; 63 | } 64 | //3.写入数据 65 | ndef.writeNdefMessage(ndefMessage); 66 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 67 | } else { //当我们买回来的NFC标签是没有格式化的,或者没有分区的执行此步 68 | //Ndef格式类 69 | NdefFormatable format = NdefFormatable.get(tag); 70 | //判断是否获得了NdefFormatable对象,有一些标签是只读的或者不允许格式化的 71 | if (format != null) { 72 | //连接 73 | format.connect(); 74 | //格式化并将信息写入标签 75 | format.format(ndefMessage); 76 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 77 | } else { 78 | Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show(); 79 | } 80 | } 81 | } catch (Exception e) { 82 | } 83 | } 84 | } -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/RunUrlActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.net.Uri; 5 | import android.nfc.NdefMessage; 6 | import android.nfc.NdefRecord; 7 | import android.nfc.NfcAdapter; 8 | import android.nfc.Tag; 9 | import android.nfc.tech.Ndef; 10 | import android.nfc.tech.NdefFormatable; 11 | import android.os.Bundle; 12 | import android.widget.Toast; 13 | 14 | import com.example.nfc.R; 15 | import com.example.nfc.base.BaseNfcActivity; 16 | 17 | /** 18 | * 自动打开网页 19 | */ 20 | public class RunUrlActivity extends BaseNfcActivity { 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_run_url); 25 | } 26 | 27 | @Override 28 | public void onNewIntent(Intent intent) { 29 | //1.获取Tag对象 30 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 31 | writeNFCTag(detectedTag); 32 | } 33 | 34 | /** 35 | * 往标签写数据的方法 36 | * 37 | * @param tag 38 | */ 39 | public void writeNFCTag(Tag tag) { 40 | if (tag == null) { 41 | return; 42 | } 43 | NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{NdefRecord 44 | .createUri(Uri.parse("http://www.baidu.com"))}); 45 | //转换成字节获得大小 46 | int size = ndefMessage.toByteArray().length; 47 | try { 48 | //2.判断NFC标签的数据类型(通过Ndef.get方法) 49 | Ndef ndef = Ndef.get(tag); 50 | //判断是否为NDEF标签 51 | if (ndef != null) { 52 | ndef.connect(); 53 | //判断是否支持可写 54 | if (!ndef.isWritable()) { 55 | return; 56 | } 57 | //判断标签的容量是否够用 58 | if (ndef.getMaxSize() < size) { 59 | return; 60 | } 61 | //3.写入数据 62 | ndef.writeNdefMessage(ndefMessage); 63 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 64 | } else { //当我们买回来的NFC标签是没有格式化的,或者没有分区的执行此步 65 | //Ndef格式类 66 | NdefFormatable format = NdefFormatable.get(tag); 67 | //判断是否获得了NdefFormatable对象,有一些标签是只读的或者不允许格式化的 68 | if (format != null) { 69 | //连接 70 | format.connect(); 71 | //格式化并将信息写入标签 72 | format.format(ndefMessage); 73 | Toast.makeText(this, "写入成功", 74 | Toast.LENGTH_SHORT).show(); 75 | } else { 76 | Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show(); 77 | } 78 | } 79 | } catch (Exception e) { 80 | } 81 | } 82 | } -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/WriteMUActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.nfc.NfcAdapter; 5 | import android.nfc.Tag; 6 | import android.nfc.tech.MifareUltralight; 7 | import android.os.Bundle; 8 | import android.widget.Toast; 9 | 10 | import com.example.nfc.R; 11 | import com.example.nfc.base.BaseNfcActivity; 12 | 13 | import java.nio.charset.Charset; 14 | 15 | public class WriteMUActivity extends BaseNfcActivity { 16 | @Override 17 | public void onCreate(Bundle savedInstanceState) { 18 | super.onCreate(savedInstanceState); 19 | setContentView(R.layout.activity_write_mu); 20 | } 21 | 22 | @Override 23 | public void onNewIntent(Intent intent) { 24 | Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 25 | String[] techList = tag.getTechList(); 26 | boolean haveMifareUltralight = false; 27 | for (String tech : techList) { 28 | if (tech.indexOf("MifareUltralight") >= 0) { 29 | haveMifareUltralight = true; 30 | break; 31 | } 32 | } 33 | if (!haveMifareUltralight) { 34 | Toast.makeText(this, "不支持MifareUltralight数据格式", Toast.LENGTH_SHORT).show(); 35 | return; 36 | } 37 | writeTag(tag); 38 | } 39 | 40 | public void writeTag(Tag tag) { 41 | MifareUltralight ultralight = MifareUltralight.get(tag); 42 | try { 43 | ultralight.connect(); 44 | //写入八个汉字,从第五页开始写,中文需要转换成GB2312格式 45 | ultralight.writePage(4, "北京".getBytes(Charset.forName("GB2312"))); 46 | ultralight.writePage(5, "上海".getBytes(Charset.forName("GB2312"))); 47 | ultralight.writePage(6, "广州".getBytes(Charset.forName("GB2312"))); 48 | ultralight.writePage(7, "天津".getBytes(Charset.forName("GB2312"))); 49 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 50 | } catch (Exception e) { 51 | } finally { 52 | try { 53 | ultralight.close(); 54 | } catch (Exception e) { 55 | } 56 | } 57 | } 58 | } 59 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/WriteTextActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.nfc.NdefMessage; 5 | import android.nfc.NdefRecord; 6 | import android.nfc.NfcAdapter; 7 | import android.nfc.Tag; 8 | import android.nfc.tech.Ndef; 9 | import android.os.Bundle; 10 | import android.widget.Toast; 11 | 12 | import com.example.nfc.R; 13 | import com.example.nfc.base.BaseNfcActivity; 14 | 15 | import java.nio.charset.Charset; 16 | import java.util.Locale; 17 | 18 | public class WriteTextActivity extends BaseNfcActivity { 19 | private String mText = "NFC-NewText-123"; 20 | 21 | @Override 22 | protected void onCreate(Bundle savedInstanceState) { 23 | super.onCreate(savedInstanceState); 24 | setContentView(R.layout.activity_write_text); 25 | } 26 | 27 | @Override 28 | public void onNewIntent(Intent intent) { 29 | if (mText == null) 30 | return; 31 | //获取Tag对象 32 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 33 | NdefMessage ndefMessage = new NdefMessage( 34 | new NdefRecord[]{createTextRecord(mText)}); 35 | boolean result = writeTag(ndefMessage, detectedTag); 36 | if (result) { 37 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 38 | } else { 39 | Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show(); 40 | } 41 | } 42 | 43 | /** 44 | * 创建NDEF文本数据 45 | * 46 | * @param text 47 | * @return 48 | */ 49 | public static NdefRecord createTextRecord(String text) { 50 | byte[] langBytes = Locale.CHINA.getLanguage().getBytes(Charset.forName("US-ASCII")); 51 | Charset utfEncoding = Charset.forName("UTF-8"); 52 | //将文本转换为UTF-8格式 53 | byte[] textBytes = text.getBytes(utfEncoding); 54 | //设置状态字节编码最高位数为0 55 | int utfBit = 0; 56 | //定义状态字节 57 | char status = (char) (utfBit + langBytes.length); 58 | byte[] data = new byte[1 + langBytes.length + textBytes.length]; 59 | //设置第一个状态字节,先将状态码转换成字节 60 | data[0] = (byte) status; 61 | //设置语言编码,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1到langBytes.length的位置 62 | System.arraycopy(langBytes, 0, data, 1, langBytes.length); 63 | //设置文本字节,使用数组拷贝方法,从0开始拷贝到data中,拷贝到data的1 + langBytes.length 64 | //到textBytes.length的位置 65 | System.arraycopy(textBytes, 0, data, 1 + langBytes.length, textBytes.length); 66 | //通过字节传入NdefRecord对象 67 | //NdefRecord.RTD_TEXT:传入类型 读写 68 | NdefRecord ndefRecord = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, 69 | NdefRecord.RTD_TEXT, new byte[0], data); 70 | return ndefRecord; 71 | } 72 | 73 | /** 74 | * 写数据 75 | * 76 | * @param ndefMessage 创建好的NDEF文本数据 77 | * @param tag 标签 78 | * @return 79 | */ 80 | public static boolean writeTag(NdefMessage ndefMessage, Tag tag) { 81 | try { 82 | Ndef ndef = Ndef.get(tag); 83 | ndef.connect(); 84 | ndef.writeNdefMessage(ndefMessage); 85 | return true; 86 | } catch (Exception e) { 87 | } 88 | return false; 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /nfc-app/src/main/java/com/example/nfc/ui/WriteUriActivity.java: -------------------------------------------------------------------------------- 1 | package com.example.nfc.ui; 2 | 3 | import android.content.Intent; 4 | import android.nfc.NdefMessage; 5 | import android.nfc.NdefRecord; 6 | import android.nfc.NfcAdapter; 7 | import android.nfc.Tag; 8 | import android.nfc.tech.Ndef; 9 | import android.os.Bundle; 10 | import android.widget.Toast; 11 | 12 | import com.example.nfc.R; 13 | import com.example.nfc.base.BaseNfcActivity; 14 | import com.example.nfc.UriPrefix; 15 | 16 | public class WriteUriActivity extends BaseNfcActivity { 17 | private String mUri = "http://www.baidu.com"; 18 | 19 | @Override 20 | public void onCreate(Bundle savedInstanceState) { 21 | super.onCreate(savedInstanceState); 22 | setContentView(R.layout.activity_write_uri); 23 | } 24 | 25 | public void onNewIntent(Intent intent) { 26 | Tag detectedTag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG); 27 | NdefMessage ndefMessage = new NdefMessage(new NdefRecord[]{createUriRecord(mUri)}); 28 | boolean result = writeTag(ndefMessage, detectedTag); 29 | if (result) { 30 | Toast.makeText(this, "写入成功", Toast.LENGTH_SHORT).show(); 31 | } else { 32 | Toast.makeText(this, "写入失败", Toast.LENGTH_SHORT).show(); 33 | } 34 | } 35 | 36 | /** 37 | * 将Uri转成NdefRecord 38 | * 39 | * @param uriStr 40 | * @return 41 | */ 42 | public static NdefRecord createUriRecord(String uriStr) { 43 | byte prefix = 0; 44 | for (Byte b : UriPrefix.URI_PREFIX_MAP.keySet()) { 45 | String prefixStr = UriPrefix.URI_PREFIX_MAP.get(b).toLowerCase(); 46 | if ("".equals(prefixStr)) 47 | continue; 48 | if (uriStr.toLowerCase().startsWith(prefixStr)) { 49 | prefix = b; 50 | uriStr = uriStr.substring(prefixStr.length()); 51 | break; 52 | } 53 | } 54 | byte[] data = new byte[1 + uriStr.length()]; 55 | data[0] = prefix; 56 | System.arraycopy(uriStr.getBytes(), 0, data, 1, uriStr.length()); 57 | NdefRecord record = new NdefRecord(NdefRecord.TNF_WELL_KNOWN, NdefRecord.RTD_URI, new byte[0], data); 58 | return record; 59 | } 60 | 61 | /** 62 | * 写入标签 63 | * 64 | * @param message 65 | * @param tag 66 | * @return 67 | */ 68 | public static boolean writeTag(NdefMessage message, Tag tag) { 69 | int size = message.toByteArray().length; 70 | try { 71 | Ndef ndef = Ndef.get(tag); 72 | if (ndef != null) { 73 | ndef.connect(); 74 | if (!ndef.isWritable()) { 75 | return false; 76 | } 77 | if (ndef.getMaxSize() < size) { 78 | return false; 79 | } 80 | ndef.writeNdefMessage(message); 81 | return true; 82 | } 83 | } catch (Exception e) { 84 | } 85 | return false; 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/drawable/nfc_read.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/drawable/nfc_read.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/drawable/nfc_run.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/drawable/nfc_run.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/drawable/nfc_write.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/drawable/nfc_write.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 7 | 8 | 12 | 13 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_read_mu.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 24 | 25 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_read_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_read_uri.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 27 | 28 | 33 | 34 | 35 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_run_app.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_run_url.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 24 | 25 | 26 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_write_mu.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 26 | 27 | 32 | 33 | 34 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_write_text.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 25 | 26 | 34 | 35 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/layout/activity_write_uri.xml: -------------------------------------------------------------------------------- 1 | 2 | 11 | 12 | 18 | 19 | 25 | 26 | 34 | 35 | 40 | 41 | 42 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/nfc-app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /nfc-app/src/main/res/values-w820dp/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | 64dp 7 | 8 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #3F51B5 4 | #303F9F 5 | #FF4081 6 | #FFFFFF 7 | 8 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/values/dimens.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 16dp 5 | 16dp 6 | 7 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | nfc-app 4 | 自动运行程序 5 | 自动打开网页 6 | 读NFC标签中的文本数据 7 | 写NFC标签中的文本数据 8 | 读NFC标签中的Uri数据 9 | 写NFC标签中的Uri数据 10 | 读NFC标签非NDEF格式的数据 11 | 写NFC标签非NDEF格式的数据 12 | -------------------------------------------------------------------------------- /nfc-app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':nfc-app' 2 | -------------------------------------------------------------------------------- /website/static/screenshot.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/jopenx/android-nfc/38535756ffe2c6e4342f2ee2de5f445b3a3c43f9/website/static/screenshot.jpg --------------------------------------------------------------------------------