尝试在NfcManager.start()上获取null数组的长度

时间:2017-10-26 09:48:14

标签: java android react-native nfc

我正在使用react native v0.49并安装了react-native-nfc-manager。 当我尝试使用nfc时,我收到错误

Attempt to get length of null array

所以我检查了nfc文件夹,我发现插件安装中存在问题

@ReactMethod
public void start(Callback callback) {
    NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
    if (nfcAdapter != null) {
        Log.d(LOG_TAG, "start");
        callback.invoke(null);
    } else {
        Log.d(LOG_TAG, "not support in this device");
        callback.invoke("no nfc support");
    }
}

你可以看到当nfcAdapter不为空时

callback.invoke(null)

所以问题就在于此,所以我尝试将其更改为

callback.invoke(LOG_TAG)

并且它没有显示错误,但我没有得到任何nfc标签,是显示未定义但不是错误。 我能做什么? 这是所有NfcManager.java文件

package community.revteltech.nfc;

import android.app.Activity;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Build;
import android.os.Bundle;
import android.support.annotation.Nullable;
import android.util.Base64;
import android.util.Log;
import android.provider.Settings;
import com.facebook.react.bridge.*;
import com.facebook.react.modules.core.RCTNativeAppEventEmitter;

import android.app.PendingIntent;
import android.content.Intent;
import android.content.IntentFilter;
import android.content.IntentFilter.MalformedMimeTypeException;
import android.net.Uri;
import android.nfc.FormatException;
import android.nfc.NdefMessage;
import android.nfc.NdefRecord;
import android.nfc.NfcAdapter;
import android.nfc.NfcEvent;
import android.nfc.Tag;
import android.nfc.TagLostException;
import android.nfc.tech.Ndef;
import android.nfc.tech.NdefFormatable;
import android.os.Parcelable;

import org.json.JSONObject;
import org.json.JSONException;

import java.util.*;

import static android.app.Activity.RESULT_OK;
import static android.os.Build.VERSION_CODES.LOLLIPOP;
import static com.facebook.react.bridge.UiThreadUtil.runOnUiThread;

class NfcManager extends ReactContextBaseJavaModule implements ActivityEventListener, LifecycleEventListener {
    private static final String LOG_TAG = "NfcManager";
    private final List<IntentFilter> intentFilters = new ArrayList<IntentFilter>();
    private final ArrayList<String[]> techLists = new ArrayList<String[]>();
    private Context context;
    private ReactApplicationContext reactContext;
    private Boolean isForegroundEnabled = false;
    private Boolean isResumed = false;

    public NfcManager(ReactApplicationContext reactContext) {
        super(reactContext);
        context = reactContext;
        this.reactContext = reactContext;
        reactContext.addActivityEventListener(this);
        reactContext.addLifecycleEventListener(this);
        Log.d(LOG_TAG, "NfcManager created");
    }

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

    @ReactMethod
    public void start(Callback callback) {
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
        if (nfcAdapter != null) {
            Log.d(LOG_TAG, "start");
            callback.invoke(null);
        } else {
            Log.d(LOG_TAG, "not support in this device");
            callback.invoke("no nfc support");
        }
    }

    @ReactMethod
    public void isEnabled(Callback callback) {
        Log.d(LOG_TAG, "isEnabled");
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
        if (nfcAdapter != null) {
            callback.invoke(null, nfcAdapter.isEnabled());
        } else {
            callback.invoke(null, false);
        }
    }

    @ReactMethod
    public void goToNfcSetting(Callback callback) {
        Log.d(LOG_TAG, "goToNfcSetting");
        Activity currentActivity = getCurrentActivity();
        currentActivity.startActivity(new Intent(Settings.ACTION_NFC_SETTINGS));
        callback.invoke();
    }

    @ReactMethod
    public void getLaunchTagEvent(Callback callback) {
        Activity currentActivity = getCurrentActivity();
        Intent launchIntent = currentActivity.getIntent();
        WritableMap nfcTag = parseNfcIntent(launchIntent);
        callback.invoke(null, nfcTag);
    }

    @ReactMethod
    private void registerTagEvent(Callback callback) {
        Log.d(LOG_TAG, "registerTag");
        isForegroundEnabled = true;

        // capture all mime-based dispatch NDEF
        IntentFilter ndef = new IntentFilter(NfcAdapter.ACTION_NDEF_DISCOVERED);
        try {
            ndef.addDataType("*/*");
        } catch (MalformedMimeTypeException e) {
            throw new RuntimeException("fail", e);
        }
        intentFilters.add(ndef);

        // capture all rest NDEF, such as uri-based
        intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TECH_DISCOVERED));
        techLists.add(new String[]{Ndef.class.getName()});

        // for those without NDEF, get them as tags
        intentFilters.add(new IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED));

        if (isResumed) {
            enableDisableForegroundDispatch(true);
        }
        callback.invoke();
    }

    @ReactMethod
    private void unregisterTagEvent(Callback callback) {
        Log.d(LOG_TAG, "registerTag");
        isForegroundEnabled = false;
        intentFilters.clear();
        if (isResumed) {
            enableDisableForegroundDispatch(false);
        }
        callback.invoke();
    }

    @Override
    public void onHostResume() {
        Log.d(LOG_TAG, "onResume");
        isResumed = true;
        if (isForegroundEnabled) {
            enableDisableForegroundDispatch(true);
        }
    }

    @Override
    public void onHostPause() {
        Log.d(LOG_TAG, "onPause");
        isResumed = false;
        enableDisableForegroundDispatch(false);
    }

    @Override
    public void onHostDestroy() {
        Log.d(LOG_TAG, "onDestroy");
    }

    private void enableDisableForegroundDispatch(boolean enable) {
        Log.i(LOG_TAG, "enableForegroundDispatch, enable = " + enable);
        NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(context);
        Activity currentActivity = getCurrentActivity();

        if (nfcAdapter != null && !currentActivity.isFinishing()) {
            try {
                if (enable) {
                    nfcAdapter.enableForegroundDispatch(currentActivity, getPendingIntent(), getIntentFilters(), getTechLists());
                } else {
                    nfcAdapter.disableForegroundDispatch(currentActivity);
                }
            } catch (IllegalStateException e) {
                Log.w(LOG_TAG, "Illegal State Exception starting NFC. Assuming application is terminating.");
            }
        }
    }

    private PendingIntent getPendingIntent() {
        Activity activity = getCurrentActivity();
        Intent intent = new Intent(activity, activity.getClass());
        intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP | Intent.FLAG_ACTIVITY_CLEAR_TOP);
        return PendingIntent.getActivity(activity, 0, intent, 0);
    }

    private IntentFilter[] getIntentFilters() {
        return intentFilters.toArray(new IntentFilter[intentFilters.size()]);
    }

    private String[][] getTechLists() {
        return techLists.toArray(new String[0][0]);
    }

    private void sendEvent(String eventName,
    @Nullable WritableMap params) {
        getReactApplicationContext()
        .getJSModule(RCTNativeAppEventEmitter.class)
        .emit(eventName, params);
    }

    private void sendEventWithJson(String eventName,
    JSONObject json) {
        try {
            WritableMap map = JsonConvert.jsonToReact(json);
            sendEvent(eventName, map);
        } catch (JSONException ex) {
            Log.d(LOG_TAG, "fireNdefEvent fail: " + ex);
        }
    }

    private final BroadcastReceiver mReceiver = new BroadcastReceiver() {
        @Override
        public void onReceive(Context context, Intent intent) {
            Log.d(LOG_TAG, "onReceive " + intent);
        }
    };

    @Override
    public void onActivityResult(Activity activity, int requestCode, int resultCode, Intent data) {
        Log.d(LOG_TAG, "onActivityResult");
    }

    @Override
    public void onNewIntent(Intent intent) {
        Log.d(LOG_TAG, "onNewIntent " + intent);
        WritableMap nfcTag = parseNfcIntent(intent);
        if (nfcTag != null) {
            sendEvent("NfcManagerDiscoverTag", nfcTag);
        }
    }

    private WritableMap parseNfcIntent(Intent intent) {
        Log.d(LOG_TAG, "parseIntent " + intent);
        String action = intent.getAction();
        Log.d(LOG_TAG, "action " + action);
        if (action == null) {
            return null;
        }

        WritableMap parsed = null;
        Tag tag = intent.getParcelableExtra(NfcAdapter.EXTRA_TAG);
        // Parcelable[] messages = intent.getParcelableArrayExtra((NfcAdapter.EXTRA_NDEF_MESSAGES));

        if (action.equals(NfcAdapter.ACTION_NDEF_DISCOVERED)) {
            Ndef ndef = Ndef.get(tag);
            Parcelable[] messages = intent.getParcelableArrayExtra((NfcAdapter.EXTRA_NDEF_MESSAGES));
            parsed = ndef2React(ndef, messages);
        } else if (action.equals(NfcAdapter.ACTION_TECH_DISCOVERED)) {
            for (String tagTech : tag.getTechList()) {
                Log.d(LOG_TAG, tagTech);
                if (tagTech.equals(NdefFormatable.class.getName())) {
                    // fireNdefFormatableEvent(tag);
                } else if (tagTech.equals(Ndef.class.getName())) { //
                    Ndef ndef = Ndef.get(tag);
                    parsed = ndef2React(ndef, new NdefMessage[] { ndef.getCachedNdefMessage() });
                }
            }
        } else if (action.equals(NfcAdapter.ACTION_TAG_DISCOVERED)) {
            parsed = tag2React(tag);
        }

        return parsed;
    }

    private WritableMap tag2React(Tag tag) {
        try {
            JSONObject json = Util.tagToJSON(tag);
            return JsonConvert.jsonToReact(json);
        } catch (JSONException ex) {
            return null;
        }

    }

    private WritableMap ndef2React(Ndef ndef, Parcelable[] messages) {
        try {
            JSONObject json = buildNdefJSON(ndef, messages);
            return JsonConvert.jsonToReact(json);
        } catch (JSONException ex) {
            return null;
        }
    }

    JSONObject buildNdefJSON(Ndef ndef, Parcelable[] messages) {
        JSONObject json = Util.ndefToJSON(ndef);

        // ndef is null for peer-to-peer
        // ndef and messages are null for ndef format-able
        if (ndef == null && messages != null) {

            try {

                if (messages.length > 0) {
                    NdefMessage message = (NdefMessage) messages[0];
                    json.put("ndefMessage", Util.messageToJSON(message));
                    // guessing type, would prefer a more definitive way to determine type
                    json.put("type", "NDEF Push Protocol");
                }

                if (messages.length > 1) {
                    Log.d(LOG_TAG, "Expected one ndefMessage but found " + messages.length);
                }

            } catch (JSONException e) {
                // shouldn't happen
                Log.e(Util.TAG, "Failed to convert ndefMessage into json", e);
            }
        }
        return json;
    }

}

我的nfc组件

import React, { Component } from 'react';
import {
    View,
    Text,
    Button,
    Platform,
    TouchableOpacity,
    Linking
} from 'react-native';
import NfcManager, {NdefParser} from 'react-native-nfc-manager';

class NFC extends Component {
    constructor(props) {
        super(props);
        this.state = {
            supported: true,
            enabled: false,
            tag: {},
        }
    }

    componentDidMount() {
        NfcManager.start({
            onSessionClosedIOS: () => {
                console.log('ios session closed');
            }
        })
        .then(result => {
            console.log('start OK', result);
        })
        .catch(error => {
            console.warn('start fail', error);
            this.setState({supported: false});
        })

        if (Platform.OS === 'android') {
            NfcManager.getLaunchTagEvent()
            .then(tag => {
                console.log('launch tag', tag);
                if (tag) {
                    this.setState({ tag });
                }
            })
            .catch(err => {
                console.log(err);
            })
            NfcManager.isEnabled()
            .then(enabled => {
                this.setState({ enabled });
            })
            .catch(err => {
                console.log(err);
            })
        }
    }

    render() {
        let { supported, enabled, tag } = this.state;
        return (
        <View style={{ flex: 1, justifyContent: 'center', alignItems: 'center' }}>
        <Text>{`Is NFC supported ? ${supported}`}</Text>
        <Text>{`Is NFC enabled (Android only)? ${enabled}`}</Text>

        <TouchableOpacity style={{ marginTop: 20 }} onPress={this._startDetection}>
        <Text style={{ color: 'blue' }}>Start Tag Detection</Text>
        </TouchableOpacity>

        <TouchableOpacity style={{ marginTop: 20 }} onPress={this._stopDetection}>
        <Text style={{ color: 'red' }}>Stop Tag Detection</Text>
        </TouchableOpacity>

        <TouchableOpacity style={{ marginTop: 20 }} onPress={this._clearMessages}>
        <Text>Clear</Text>
        </TouchableOpacity>

        <TouchableOpacity style={{ marginTop: 20 }} onPress={this._goToNfcSetting}>
        <Text >Go to NFC setting</Text>
        </TouchableOpacity>

        <Text style={{ marginTop: 20 }}>{`Current tag JSON: ${JSON.stringify(tag)}`}</Text>
        </View>
        )
    }

    _onTagDiscovered = tag => {
        console.log('Tag Discovered', tag);
        this.setState({ tag });
        let url = this._parseUri(tag);
        if (url) {
            Linking.openURL(url)
            .catch(err => {
                console.warn(err);
            })
        }
    }

    _startDetection = () => {
        NfcManager.registerTagEvent(this._onTagDiscovered)
        .then(result => {
            console.log('registerTagEvent OK', result)
        })
        .catch(error => {
            console.warn('registerTagEvent fail', error)
        })
    }

    _stopDetection = () => {
        NfcManager.unregisterTagEvent()
        .then(result => {
            console.log('unregisterTagEvent OK', result)
        })
        .catch(error => {
            console.warn('unregisterTagEvent fail', error)
        })
    }

    _clearMessages = () => {
        this.setState({tag: null});
    }

    _goToNfcSetting = () => {
        if (Platform.OS === 'android') {
            NfcManager.goToNfcSetting()
            .then(result => {
                console.log('goToNfcSetting OK', result)
            })
            .catch(error => {
                console.warn('goToNfcSetting fail', error)
            })
        }
    }

    _parseUri = (tag) => {
        let result = NdefParser.parseUri(tag.ndefMessage[0]),
        uri = result && result.uri;
        if (uri) {
            console.log('parseUri: ' + uri);
            return uri;
        }
        return null;
    }
}
export default NFC;

1 个答案:

答案 0 :(得分:1)

请注意, NFC无法在所有设备中使用,因此您必须先检查:

  protected void onCreate(Bundle savedInstanceState) {
     super.onCreate(savedInstanceState);

     NfcAdapter nfcAdapter = NfcAdapter.getDefaultAdapter(this);
     if (nfcAdapter == null){ 
        Toast.makeText(this, "NFC not available", Toast.LENGTH_SHORT).show();
        return;  
     }else{
          Toast.makeText(this, "NFC is avalable", Toast.LENGTH_SHORT).show();
     }
     ....
     ....
 }

如果NFC不存在,那将是获取错误消息的原因:

  

尝试在NfcManager.start()

上获取null数组的长度