在 Android 应用中同时使用 QR 和 NFC 技术
Using QR and NFC technology together in an Android app
目前我正在开发一个包含两个活动的 Android 应用程序。第一个 activity (MainActivity) 在启动应用程序或扫描二维码时启动。当用户按下按钮时,MainActivity 启动第二个 activity (NFCActivity)。 NFCActivity等待用户点击一个NFC token,从token中读取数据,returns将读取的数据发送到MainActivity.
如果应用程序是手动启动的,这会很好地工作。如果应用程序是通过扫描二维码启动的,点击 NFC 标签不会像预期那样调用 NFCActivity 的 onNewIntent() 方法,而是在顶部创建一个新的 NFCActivity 实例已经显示的那个。
调用了enableForegroundDispatch()方法,应该设置FLAG_ACTIVITY_SINGLE_TOP。下面提供了一个最小示例的相关源代码。任何帮助将不胜感激!
主要Activity:
public class MainActivity extends Activity {
private EditText dataRead;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
dataRead = (EditText) findViewById(R.id.data);
final Button readKeyButton = (Button) findViewById(R.id.readNFC);
readKeyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent keyIntent = new Intent(MainActivity.this,
NFCActivity.class);
keyIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(keyIntent, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (requestCode == 1) {
String result = intent.getExtras().getString("resultData");
this.dataRead.setText(result);
}
}
}
主要 Activity 的 GUI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/readNFC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="127dp"
android:text="Read NFC Tag" />
<EditText
android:id="@+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/readNFC"
android:layout_centerHorizontal="true"
android:layout_marginBottom="85dp"
android:ems="10" >
<requestFocus />
</EditText>
</RelativeLayout>
NFCActivity:
public class NFCActivity extends Activity {
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.read_nfc);
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();
if (mAdapter != null)
mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters,
mTechLists);
}
@Override
public void onPause() {
super.onPause();
if (mAdapter != null)
mAdapter.disableForegroundDispatch(this);
}
@Override
public void onNewIntent(Intent intent) {
Log.d("TEST", "onNewIntent() called.");
// READ THE NFC TAG HERE [SKIPPED FOR MINIMAL EXAMPLE]
// Return dummy data for test
Intent result = new Intent();
result.putExtra("resultData", "DUMMY DATA");
setResult(1, result);
finish();
}
}
NFCActivity 的 GUI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#303030"
android:paddingLeft="30dp"
android:paddingRight="30dp" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Tap your NFC tag.."
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF8811"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.nfcqrtest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="test.nfcqrtest.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="test.org" android:pathPrefix="/testapp" />
</intent-filter>
</activity>
<activity
android:name=".NFCActivity"
android:windowSoftInputMode="stateHidden" android:screenOrientation="portrait" android:launchMode="singleTop">
</activity>
</application>
</manifest>
以防有人遇到类似问题:我终于能够通过将 MainActivity
的 android:launchMode
属性 设置为 singleInstance
来解决上述问题.
目前我正在开发一个包含两个活动的 Android 应用程序。第一个 activity (MainActivity) 在启动应用程序或扫描二维码时启动。当用户按下按钮时,MainActivity 启动第二个 activity (NFCActivity)。 NFCActivity等待用户点击一个NFC token,从token中读取数据,returns将读取的数据发送到MainActivity.
如果应用程序是手动启动的,这会很好地工作。如果应用程序是通过扫描二维码启动的,点击 NFC 标签不会像预期那样调用 NFCActivity 的 onNewIntent() 方法,而是在顶部创建一个新的 NFCActivity 实例已经显示的那个。
调用了enableForegroundDispatch()方法,应该设置FLAG_ACTIVITY_SINGLE_TOP。下面提供了一个最小示例的相关源代码。任何帮助将不胜感激!
主要Activity:
public class MainActivity extends Activity {
private EditText dataRead;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_start);
dataRead = (EditText) findViewById(R.id.data);
final Button readKeyButton = (Button) findViewById(R.id.readNFC);
readKeyButton.setOnClickListener(new View.OnClickListener() {
public void onClick(View v) {
Intent keyIntent = new Intent(MainActivity.this,
NFCActivity.class);
keyIntent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP);
startActivityForResult(keyIntent, 1);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode,
Intent intent) {
if (requestCode == 1) {
String result = intent.getExtras().getString("resultData");
this.dataRead.setText(result);
}
}
}
主要 Activity 的 GUI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:paddingBottom="@dimen/activity_vertical_margin"
android:paddingLeft="@dimen/activity_horizontal_margin"
android:paddingRight="@dimen/activity_horizontal_margin"
android:paddingTop="@dimen/activity_vertical_margin"
tools:context=".MainActivity" >
<Button
android:id="@+id/readNFC"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentBottom="true"
android:layout_centerHorizontal="true"
android:layout_marginBottom="127dp"
android:text="Read NFC Tag" />
<EditText
android:id="@+id/data"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_above="@+id/readNFC"
android:layout_centerHorizontal="true"
android:layout_marginBottom="85dp"
android:ems="10" >
<requestFocus />
</EditText>
</RelativeLayout>
NFCActivity:
public class NFCActivity extends Activity {
private NfcAdapter mAdapter;
private PendingIntent pendingIntent;
private IntentFilter[] mFilters;
private String[][] mTechLists;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.read_nfc);
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();
if (mAdapter != null)
mAdapter.enableForegroundDispatch(this, pendingIntent, mFilters,
mTechLists);
}
@Override
public void onPause() {
super.onPause();
if (mAdapter != null)
mAdapter.disableForegroundDispatch(this);
}
@Override
public void onNewIntent(Intent intent) {
Log.d("TEST", "onNewIntent() called.");
// READ THE NFC TAG HERE [SKIPPED FOR MINIMAL EXAMPLE]
// Return dummy data for test
Intent result = new Intent();
result.putExtra("resultData", "DUMMY DATA");
setResult(1, result);
finish();
}
}
NFCActivity 的 GUI:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="fill_parent"
android:layout_height="fill_parent"
android:background="#303030"
android:paddingLeft="30dp"
android:paddingRight="30dp" >
<TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_centerHorizontal="true"
android:layout_centerVertical="true"
android:text="Tap your NFC tag.."
android:textAppearance="?android:attr/textAppearanceLarge"
android:textColor="#FF8811"
android:textSize="30sp"
android:textStyle="bold" />
</RelativeLayout>
AndroidManifest.xml:
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="test.nfcqrtest"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="16"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.NFC" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="test.nfcqrtest.MainActivity"
android:label="@string/app_name">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" android:host="test.org" android:pathPrefix="/testapp" />
</intent-filter>
</activity>
<activity
android:name=".NFCActivity"
android:windowSoftInputMode="stateHidden" android:screenOrientation="portrait" android:launchMode="singleTop">
</activity>
</application>
</manifest>
以防有人遇到类似问题:我终于能够通过将 MainActivity
的 android:launchMode
属性 设置为 singleInstance
来解决上述问题.