React Native android: App opened with Intent, Pass

2019-07-09 06:48发布

问题:

I need to read NFC Tag ID in react native android app. I tried using nfc-react-native module but unfortunately it didn't work for me. So I've edited it.

I went through all documentations / articles about using NFC tag in react-native, writing custom android (native) components for react native but no success.

With help of some other questions here, I could manage to register the app to run when a NFC Tag have been tapped to the device. But I couldn't pass the Intent data to javascript. I read somewhere that I need to register the activity to receive the Intent. But I don't have any native activity.

I'd really appreciate your time and attention. I've been working so long on it without any success.

Here is the code : This is a custom module to read NFC tag ( edited nfc-react-module )

package es.tiarg.nfcreactnative;
import com.facebook.react.bridge.ActivityEventListener;
import com.facebook.react.bridge.ReactApplicationContext;
import com.facebook.react.bridge.ReactContext;
import com.facebook.react.bridge.ReactContextBaseJavaModule;
import com.facebook.react.bridge.ReactMethod;
import com.facebook.react.bridge.WritableMap;
import com.facebook.react.bridge.WritableArray;
import com.facebook.react.bridge.ReadableMap;
import com.facebook.react.bridge.ReadableArray;
import com.facebook.react.bridge.ReadableNativeArray;
import com.facebook.react.bridge.Arguments;
import com.facebook.react.bridge.Promise;
import com.facebook.react.bridge.Callback;
import com.facebook.react.bridge.WritableNativeArray;
import com.facebook.react.bridge.WritableNativeMap;
import com.facebook.react.bridge.LifecycleEventListener;
import com.facebook.react.modules.core.DeviceEventManagerModule;
import static com.facebook.common.util.Hex.hexStringToByteArray;

import android.app.Activity;
import android.content.Intent;
import android.nfc.NfcAdapter;
import android.nfc.Tag;
import android.nfc.tech.MifareClassic;
import android.support.annotation.Nullable;
import android.util.Log;
import android.content.Context;
import android.content.ServiceConnection;
import android.os.RemoteException;
import static android.R.attr.data;
import static android.R.attr.defaultValue;
import static android.R.attr.x;

import java.io.PrintWriter;
import java.io.StringWriter;
import java.math.BigInteger;
import java.nio.ByteBuffer;
import java.nio.IntBuffer;
import java.util.Collection;
import java.util.HashMap;
import java.util.Map;

class NfcReactNativeModule extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
    private ReactApplicationContext reactContext;

    private NfcAdapter mNfcAdapter;
    final protected static char[] HAX_ARRAY = "0123456789ABCDEF".toCharArray();
    public static final String TAG = "NFCCardID";

    public NfcReactNativeModule(ReactApplicationContext reactContext) {
        super(reactContext);
        this.reactContext = reactContext;
        this.reactContext.addActivityEventListener(this);
        this.reactContext.addLifecycleEventListener(this);

    }

    @Override
    public void onNewIntent(Intent intent) {
      Log.i(TAG, "got new intent");
      handleIntent(intent);
    }

    public void handleIntent(Intent intent) {
      String action = intent.getAction();
      Log.i(TAG, "New intent action:" + action);

      if(NfcAdapter.ACTION_TAG_DISCOVERED.equals(action) || NfcAdapter.ACTION_NDEF_DISCOVERED.equals(action)) {
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        byte[] id = tag.getId();
        String serialNumber = bytesToHex(id);
        WritableMap idData = Arguments.createMap();
        idData.putString("id", serialNumber);
        sendEvent(this.reactContext, "NFCCardID", idData);
        Log.i(TAG, "Serial number from nfc:" + serialNumber);
  		} else {
        Log.i(TAG, "Error:" + action);
      }
    }

    @Override
    public void onHostResume() {
        // Activity `onResume`
    }

    @Override
    public void onHostPause() {
        // Activity `onPause`
    }

    @Override
    public void onHostDestroy() {
        // Activity `onDestroy`
    }

    private static String bytesToHex(byte[] bytes) {
        char[] hexChars = new char[bytes.length * 2];
        for ( int j = 0; j < bytes.length; j++ ) {
            //int v = bytes[j] & 0xFF;
            int v = bytes[bytes.length - j - 1] & 0xFF;
            hexChars[j * 2] = HAX_ARRAY[v >>> 4];
            hexChars[j * 2 + 1] = HAX_ARRAY[v & 0x0F];
        }
        return new String(hexChars);
    }

    @Override
    public void onActivityResult(
      final Activity activity,
      final int requestCode,
      final int resultCode,
      final Intent intent) {
        //intent.getData();
        Log.i(TAG, "Data received from Intent:" + intent.getData());
    }

    @Override
    public String getName() {
        return "NfcReactNative";
    }

    private void sendEvent(ReactContext reactContext, String eventName, @Nullable WritableMap params) {
      reactContext
      .getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
      .emit(eventName, params);
    }
}

AndroidManifest.xml

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="net.****APPNAME*****.android.client"
    android:versionCode="4"
    android:versionName="2.1">

    <uses-permission android:name="android.permission.INTERNET" />
    <uses-permission android:name="android.permission.BLUETOOTH"/>
    <uses-permission android:name="android.permission.SYSTEM_ALERT_WINDOW"/>
    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />
    <uses-permission android:name="android.permission.NFC" />

    <uses-permission android:name="android.permission.WAKE_LOCK" />
    <permission
        android:name="${applicationId}.permission.C2D_MESSAGE"
        android:protectionLevel="signature" />
    <uses-permission android:name="${applicationId}.permission.C2D_MESSAGE" />
    <uses-permission android:name="android.permission.VIBRATE" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED"/>

    <uses-sdk
        android:minSdkVersion="16"
        android:targetSdkVersion="22" />

    <application
      android:name=".MainApplication"
      android:allowBackup="true"
      android:label="@string/app_name"
      android:icon="@mipmap/****APPNAME*****"
      android:theme="@style/SplashTheme">

      <activity
        android:name=".MainActivity"
        android:label="@string/app_name"
        android:configChanges="keyboard|keyboardHidden|orientation|screenSize">
        <intent-filter>
            <action android:name="android.intent.action.MAIN" />
            <category android:name="android.intent.category.LAUNCHER" />
        </intent-filter>
        <intent-filter android:label="filter_react_native">
          <action android:name="android.intent.action.VIEW" />
          <category android:name="android.intent.category.DEFAULT" />
          <category android:name="android.intent.category.BROWSABLE" />
          <data android:scheme="****APPNAME*****" />
        </intent-filter>
        <intent-filter>
          <action android:name="android.nfc.action.TECH_DISCOVERED"/>
        </intent-filter>

          <meta-data android:name="android.nfc.action.TECH_DISCOVERED"
              android:resource="@xml/nfc_tech_filter" />
      </activity>
      <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />

      <receiver
            android:name="com.google.android.gms.gcm.GcmReceiver"
            android:exported="true"
            android:permission="com.google.android.c2dm.permission.SEND" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
                <category android:name="${applicationId}" />
            </intent-filter>
        </receiver>

        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationPublisher" />
        <receiver android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationBootEventReceiver">
            <intent-filter>
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>
        <service android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationRegistrationService"/>
        <service
            android:name="com.dieam.reactnativepushnotification.modules.RNPushNotificationListenerService"
            android:exported="false" >
            <intent-filter>
                <action android:name="com.google.android.c2dm.intent.RECEIVE" />
            </intent-filter>
        </service>


    </application>

</manifest>

android/app/src/main/res/xml/nfc_tech_filter.xml

<resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2">
    <tech-list>
        <tech>android.nfc.tech.IsoDep</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcA</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcB</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcF</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcV</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.Ndef</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NdefFormatable</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareClassic</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.MifareUltralight</tech>
    </tech-list>
    <tech-list>
        <tech>android.nfc.tech.NfcBarcode</tech>
    </tech-list>
</resources>

Javascript/ react native side

import {
  NativeModules,
  DeviceEventEmitter
} from 'react-native';

DeviceEventEmitter.addListener('NFCCardID', function (data) {
      console.log(data);
    });

Thanks in advance.