Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

"Operación cancelada" when pressing button for getCardId() call #3

Closed
Raimmaster opened this issue Dec 18, 2016 · 24 comments
Closed

Comments

@Raimmaster
Copy link

I'm trying to test this module in an RN app we're working on. I have no idea how to implement a dynamic event so it detects the card when it is approached. Regardless, I'm trying to force it by binding it to the onPress event of a button we have. This is the specific commit I've made (and by extension, you can check the repo of the app): ebenezer-unitec/ReactNativeSBO@2f430c3

Any help, direction as to how the function should be implemented would be greatly appreciated.

Y también podemos continuar esto en españo, si llega a ser más fácil para ambos, jaja.

@Raimmaster Raimmaster changed the title "Operación cancelada" when pressing button "Operación cancelada" when pressing button for getCardId() call Dec 18, 2016
@lube
Copy link
Owner

lube commented Dec 18, 2016

We can continue in english or spanish 😝

So, what we do is trigger the read/write/id functions on lifecycle (or sagas) in some routes.

You could easily change the module to work with an event emitter if that sounds more comfortable, you should think a little bit more about the api but it should'nt be so much work from this example.

@Raimmaster
Copy link
Author

I have never done such an event emitter in RN; point is, I have my own NFC app in Android (native SDK), and it detects the card automatically. My problem is, I have no idea how to call that event automatically, how to emit such an event when the NFC card is approached. Any direction that you show me for this without necessarily giving code out would help.

@Raimmaster
Copy link
Author

Also, I have no idea what you mean by lifecycle/cycle in this case.

@lube
Copy link
Owner

lube commented Dec 18, 2016

The thing is, the event is going to trigger automatically whenever a tag is approached, so what you want to do is handling those events ('intents' on android language). In order to handle those events, I thought about two ways of aproaching the problem.

  1. Event Emmiter

DeviceEventEmitter('some-event', function () {} /* callback function when event happens */)

  1. Promise

readTag(some, data, for, the, module).then(function() {} /data/)

The event emitter looks like a cleaner way because you need to constantly have a promise ready to fetch the intent, the problem is, you have many operations with a tag (read, write, etc) and I couldnt find a comfortable api with a event emiter.

Lifecycle refers to normal react components hooks (componentDidMount, etc)

@Raimmaster
Copy link
Author

I think I'm getting the hang of what you mean. I don't have to write to the tag; I only need to read from it, and that's enough. In that case, what I need is the following, right? https://facebook.github.io/react-native/docs/native-modules-android.html#sending-events-to-javascript

Basically, add a listener to the current window (in such a case, this), and then let that event be called when it detects an NFC tag, right?

@lube
Copy link
Owner

lube commented Dec 18, 2016

Exactly you can use the readTag promise, or modify this module to use a eventemitter (remember you still need a way to pass keys + sectors/blocks to the event emitter function) (maybe an initialization function)

The main java file is 100 lines should'nt be really too hard to follow it ignoring my lame java skills

@Raimmaster
Copy link
Author

I've never used a promise in such a callback function.

componentWillMount: function() { DeviceEventEmitter.addListener('keyboardWillShow', getCardId() .then((card) => { console.log(card) }).catch((err) => { console.log(err) }) });

Would it be like that, or what is the correct way of adding the listener of the fulfilled promise?

@lube
Copy link
Owner

lube commented Dec 18, 2016

Mostly right just

componentWillMount: function () { getCardId().then((card) => console.log(card))
                                             .catch((err) => console.log(err)) }

@Raimmaster
Copy link
Author

Thanks, I'm going to try it out now.

By the way, in your README, you state that we have to create an XML file in the res folder, yet I'm not sure what should the name of the file be (I tried with "nfc_tech_filter", but it when I generated the Android project, it said that it couldn't find such a file from the metadata section of the Manifest).

@atasmohammadi
Copy link

Have you find a solution? I also need to read the card id but i don't know how.

@joostmakaay
Copy link

joostmakaay commented Jan 5, 2017

Hey, i've implemented the solution you posted above (componentWillMount), the NFC-listener will trigger(reload the scene) when I use a Tag, but the GetCardId() event won't return anything besides Operation Cancelda, do you have any idea what could cause this? Or could you post an example project online? @lube

@atasmohammadi
Copy link

@lube it would be great if you could add deviceventemitter to your module. an event listener which triggers when i tag is readed.

@fuxianwei
Copy link

I am also in study react native read NFC tags, this project gives me some ideas, but I suggest that the error "Operaci n cancelada" when directly with the getCardId library to read the information, when you close NFC equipment in react native prison in how to listen to this event, I hope to get your help. Thank you
@lube

@joostmakaay
Copy link

@ataomega @fuxianwei hey guys, if you're still struggling with this, i've solved my problem by setting the android:launchMode=singleInstance of the activity. This way the library will return more than only the warning 'Operation Cnacelda'

@atasmohammadi
Copy link

atasmohammadi commented Jan 10, 2017 via email

@joostmakaay
Copy link

joostmakaay commented Jan 10, 2017

@ataomega , The solution we've found is definitely not the way it should be done, but we needed working NFC for react-native asap.

I've removed all the functions from the NfcReactNativeModule.java except for the GetCardID:
`
public NfcReactNativeModule(ReactApplicationContext reactContext) {
super(reactContext);
this.nfcCode = "";
this.reactContext = reactContext;
this.reactContext.addActivityEventListener(this);
this.operation = OP_NOT_READY;
}

@Override
public void onNewIntent(Intent intent) {
    if (this.operation.equals(OP_NOT_READY)) {
        return;
    }
    
    MifareClassic tag = MifareClassic.get( (Tag)intent.getParcelableExtra(NfcAdapter.EXTRA_TAG));
    try {
        tag.connect();
        ByteBuffer bb = ByteBuffer.wrap(tag.getTag().getId());
        this.nfcCode = byteArrayToHexString(bb.array());
    } catch (Exception ex) {
        StringWriter sw = new StringWriter();
        PrintWriter pw = new PrintWriter(sw);
        this.tagPromise.reject(sw.toString(), ex.getMessage());
    } finally {
        this.operation = OP_NOT_READY;
    }
}

`
on a new Intent the cardID will be written to a String, in the getCardId function I do the following:

` @ReactMethod
public void getCardId(Promise promise) {
this.cancelOperation();
this.operation = OP_ID;
this.tagPromise = promise;
}

private void cancelOperation () {
    if (!this.operation.equals(OP_NOT_READY)) {
        this.tagPromise.reject(this.nfcCode);
        this.nfcCode = "";
        this.operation = OP_NOT_READY;
    }
}

`
The tagPromise.Reject will return an error the the GetCardId-call I did in my ReactNative project, since I couldn't get tagPromise.Resolve to work (so it would return in the promise of the GetCardId-call.

Here is my AndroidManifest.xml

`

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

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

<application
  android:name=".MainApplication"
  android:allowBackup="true"
  android:label="@string/app_name"
  android:icon="@mipmap/ic_launcher"
  android:theme="@style/AppTheme">
  <activity
    android:name=".MainActivity"
    android:launchMode="singleInstance"
    android:label="@string/app_name"
    android:screenOrientation="landscape"
    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>
        <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" />

    <intent-filter>
        <action android:name="android.nfc.action.TAG_DISCOVERED" />
    </intent-filter>
  </activity>

  <activity android:name="com.facebook.react.devsupport.DevSettingsActivity" />
</application>
`

and since I couldn't get a eventlistener working, i've made timer function that will execute GetCardId every x miliseconds, so nfcCode will be retrieved if it's set:

`
componentDidMount: function(){
this.startNFCloop();
},

startNFCloop: function(){
    var self = this;
    setTimeout(function() {
    if (!self.isMounted()) { return; } // abandon 
        //self.callback(); // do it once and then start it up ...
    self._timer = setInterval(self.nfcCallback.bind(self), 1000);
    }, 1000);    
},

nfcCallback: function(){
   getCardId().then((card) => {
    }).catch((err) => {
        // NFCcode isset, do something
        if (err.message > "") {
            this.login(err.message);
        }
    });
},`

I don't recommend using this code, since it's very hacky and not the way a module should be used.

@atasmohammadi
Copy link

atasmohammadi commented Jan 10, 2017 via email

@Raimmaster
Copy link
Author

Thanks for the heads up, @joostmakaay. Any direction of working implementations are welcome.

@atasmohammadi
Copy link

atasmohammadi commented Jan 13, 2017

@joostmakaay Please take a look at here : http://stackoverflow.com/questions/41615851/react-native-android-nfc-getting-card-id

I've edited it to use sendEvent

@Raimmaster
Copy link
Author

@joostmakaay, I've tried to implement your solution in this repo https://github.com/ebenezer-unitec/ReactNativeSBO/, using it specifically in this file: https://github.com/ebenezer-unitec/ReactNativeSBO/blob/NFC_Test/src/components/scanner/scanningView.js

Now, I don't know if I've been implementing it well, as I've been editing the other files you said (and those have been added to the .gitignore, due to them being in the .node_modules directory). Would you mind helping us notice what is that we're doing wrong in implementing your solution? Please.

@joostmakaay
Copy link

@Raimmaster checked your repo quick, first thing I noticed is that you didn't modify AndroidManifest/MainApplication files, if you don't add the reference to the NFC node_module the code won't get compiled, and by adding the NFC-intentfilter to the AndroidManifest, the app can't detect a NFC trigger from Android. if you copy those things from my example, i think you will be a step further in getting it working.

@Raimmaster
Copy link
Author

I've added all the configurations as you said, and while it has been a progress (now it compiles correctly, and my cellphone asks whether to use the "New tag detected" action Android already has implemented, or the application I'm developing), it still does not detect the ID, apparently. It's pretty much an infinite alert of "Operación Cancelada", @joostmakaay. You may check the repo again to see if we've missed something again. Same branch, NFC_Test.

@Raimmaster
Copy link
Author

This is my NfcReactiveModule.java file, by the way: http://pastebin.com/Hkw2Wrjz

@lube
Copy link
Owner

lube commented Feb 2, 2017

Hey guys, sorry for being absent in this discussion, I made an API overhaul to work with event emmiters and allow multiple readings and writes with only one intent, I also included a sample project so you cant try it.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants