Why are directory methods in path_provider awaited like so? They are not over the internet calls to the network.
Directory tempDir = await getTemporaryDirectory();
String tempPath = tempDir.path;
Directory appDocDir = await getApplicationDocumentsDirectory();
String appDocPath = appDocDir.path;
Edit:
I don't think I was specific enough. I understand from the method signature that it returns a future. I was more asking as to why it is a future, why the methods are asynchronous.
Is it because they are kind of like unix file system writes/reads, ie blocking?
Because the underlying code is asynchronous, and returns a Future. To get the value returned from a Future you must either use await or .then().
path_provider uses MethodChannel to call native code, and the MethodChannel.invokeMethod() function is asynchronous. Specifically, the interface to native code (platform channels) works by sending a message and waiting for a response. It does this asynchronously so it does not lock up your app while waiting for your request to complete on the native side.
Flutter’s platform-specific API support does not rely on code generation, but rather on a flexible message passing style:
The Flutter portion of the app sends messages to its host, the iOS or Android portion of the app, over a platform channel.
The host listens on the platform channel, and receives the message. It then calls into any number of platform-specific APIs—using the native programming language—and sends a response back to the client, the Flutter portion of the app.
Futures and asynchronous code are not just for network/internet related work.
path_provider's API is asynchronous because it communicates with platform-native Android or iOS code, and Flutter uses an asynchronous message-passing system for that communication.
Related
I integrated Sinch SDK into iOS application (Capacity plugin which works under ionic).
Main use case so far is to make call from App to phone.
I followed instructions from here: https://developers.sinch.com/docs/in-app-calling/getting-started/ios/create-app/ and everything works correctly - I can call from the app to phones using Sinch platform.
The problem which I noticed is when callee rejects the call then app does not receive immediate notification about it. Sometimes notification (func callDidEnd(_ call: SinchRTC.SinchCall)) is triggered after some delay (10-20s). However sometimes when callee rejects the call app is still calling and second connection appears on callee's phone - then when second time callee rejects the call app correctly receive callback about it and close the connection.
Do you have any hints what can be the issue here?
We will review the tutorial to see if the issue can be replicated.
However using the VideoCallKitSwift Swift sample you can change the following to the sinch client on start and call invocation to make a PSTN call:
In CallKitMediator
add the cli:<YOURCLI> after userId in the SinchRTC.client (In this case I have put a placeholder +4100000000 in the cli)
From
do {
self.client = try SinchRTC.client(withApplicationKey: APPLICATION_KEY,
environmentHost: ENVIRONMENT_HOST,
userId: userId)
To
do {
self.client = try SinchRTC.client(withApplicationKey: APPLICATION_KEY,
environmentHost: ENVIRONMENT_HOST,
userId: userId,
cli:"+4100000000")
In CallKitMediator+CXProviderDelegate Here remove the withId: and change the client method to callPhoneNumber instead of videoCallToUser
From
let callResult = self.client!.callClient.videoCallToUser(withId: action.handle.value)
To
let callResult = self.client!.callClient.callPhoneNumber(action.handle.value)
Testing to a PSTN connection via this method yields no delay in the callDidEnd. If your issues persist, I would recommend to open a ticket with Sinch support who can analyse the PSTN leg of the call for you.
Context & Problem:
I’m writing a React Native application which has to communicate with NFC MiFare Ultralight tags. I have NXP NTAG I2C PLUS ISO14443-3 tags.
I’m using the react-native-nfc-manager library for this. On android I didn’t notice any problems just on the iOS side. I’m testing on iOS 13 and 14 and my device is an iPhone 7.
I am able to find and connect to NFC Mifare Ultralight tags (can read and write them too), but in the 75% of the situations I get the following error during the communications:
[CoreNFC] 00000002 803f43f0 -[NFCTagReaderSession transceive:tagUpdate:error:]:771 Error Domain=NFCError Code=100 "Tag connection lost" UserInfo={NSLocalizedDescription=Tag connection lost}
This problem only appears on iOS. Android works fine.
How I communicate:
I added the NDEF and TAG formats to the entitlements file to the …readersession.formats.
I also added value to the info.plist for the Privacy - NFC Scan Usage Description.
I’m requesting NfcTech.MifareIOS tech and calling the NfcManager.sendMifareCommandIOS() method as the library’s MiFare example shows. I’ve tried to use other transmitter methods and requesting other tech types, but in those situations I didn’t even get any responses.
This is how I create the writing commands and how I call my transmit method:
// WRITE COMMAND looks like: [0xA2, Addr, datas]
const writeCommand = [0xa2, offset, data[0], data[1], data[2], data[3]];
const response = await this.transmit(writeCommand);
This is how I create the reading commands:
// FAST_READ COMMAND looks like: [0x3A, StartAddr, EndAddr]
const readCommand = [0x3a, offset, offset + readLength];
And here is my transmit method:
private async transmit(msg: number[]): Promise<number[]> {
...
const cmd = Platform.OS === 'ios' ? NfcManager.sendMifareCommandIOS : NfcManager.transceive;
return await cmd(msg);
}
What I noticed and tried:
I noticed that the iPhone is very sensitive for the positioning. If I hold the device in a certain position I can also achieve 80% success. I noticed too that if I leave the phone on the tag I get this error more often. I got better results when I took away the phone after a communication and then put it back again.
When I added some sleep after the communication for example 100 ms, the communication seemed to be more stable. Because of the number of communications, I can't wait that much. Even if I wait I get the error, but fewer times.
I saw a very similar issue which describes a CRC problem, which appears when you try to send CRC, but that has been automatically added already by the iOS. I’m not sending the CRC (which was the solution in the mentioned issue), so that shouldn't be a problem.
Also saw the following issue with similar problem, but I have another type of tags - ISO-14443 and I'm also able to connect and communicate with the tags which wasn't the case in the mentioned issue.
Tried to invalidate the session after each communication, but didn’t help to stabilize the connection.
Tried with multiple tags (but with the same tag type), but got the same results.
I'd appreciate very much any ideas that could help me solve this problem.
At the end I managed to try out our app on multiple iPhones and the NFC worked properly.
We also found out that our test device is a refurbished unit and we think that maybe that is the problem's cause.
I have been trying to work with https://github.com/cordova-sms/cordova-sms-plugin
For Android, it works as expected. Unfortunately, I can't capture the activity for ios and windows. It opens the Messages app (as we know) but it doesn't wait for the Messages response whether it has been sent, canceled, or failed.
It always response success. I am already using async (work on Android).
That's because I can't use the success and error parameters.
It only accepts 3 parameters:
sms.send(number, message, options);
It doesn't accept 5 parameters:
sms.send(number, message, options, success, error);
Error message is:
[ts] Expected 2-3 arguments, but got 5.
(method) SMS.send(phoneNumber: string | string[], message: string, options?: SmsOptions): Promise<any>
Has anyone able to capture Canceled SMS with this or other plugins?
P.S. I tried using other plugins but it can't even send.
According to your error-message (and your tags) you are using the cordova-plugin with ionic-native. In this case you do not need to pass a success/error callback because the ionic-team built a nice wrapper for it so it supports promise callbacks (docs for the .send() method).
To use it you have to modify your code as follows:
sms.send(number, message, options).then(
success => {
console.log(success);
},
error => {
console.log(error);
},
);
Please be aware that the callbacks only work correctly on iOS for this plugin. On the Android platform it will always return success immediately because of limitations of the operating system. For more see this FAQ on their github page.
0
Google changed the policy regarding to SMS access, so the direct reading of incoming SMS is no longer allowed and the associated permissions will be removed (SMS_READ).
Now, it is necessary to use the Android SMS Retriever API your SMS message needs to comply a specific format in order to be intercepted by your app.
In Cordova use this plugin to easily read incoming SMS:
cordova plugin add cordova-plugin-android-sms-retriever Github: https://github.com/diegosiao/cordova-plugin-android-sms-retriever
TLDR: Is there some way I can use a callback or get a return value from react to my native code (iOS)? Or can I use a set of locks to enforce ordering for eventdispatcher and eventemitter listeners to enforce an ordering?
More Information:
So I'm using the event dispatcher in my iOS code (self.bridge.eventDispatcher) and that's working great. I'm able to send events with information to my react code.
However, I noticed that this works asynchronously. I currently use this because if I require information on my iOS side, I send a ping to my react side requesting this information. I then lock upon the request and wait for my react code to use NativeModules and invoke an iOS method where I get the requested data.
Basically, enforcing a synchronous pattern feels a little dangerous because I'm not sure whether bridging methods can fail. For example, I can send an event to react and then lock. If my react side does not get it, or fails to send a notification to the iOS side, then I will never unlock and then will have deadlock. So to this, I have two questions. Is bridging reliable enough to avoid deadlocking through this method? Or is there a better way to accomplish the same result and request information from my react side from my iOS code?
Awesome so I got it, turns out there's a structure called RCTResponseSenderBlock. I made another
iOS method:
-(void)tmpMethod:(RCTResponseSenderBlock)callback{
[self.bridge.eventDispatcher sendAppEventWithName:#"channel" body:#{#"Block":callback}
] ;
}
javascriptReciever:
EventEmitter.addListener("channel", async event => {
console.log(event)
event.Block(["Hello There"]);
return;
});
ios Method Invocation:
[self tmpMethod:^(NSArray* response){
NSLog((NSString*)[response objectAtIndex:0]); //prints Hello There
}];
UPDATE
Turns out when I try to do the same for Android, I can't. The Android platform uses WriteableMap or WriteableArray to send events using the following method:
private void sendEvent(ReactContext reactContext,
String eventName,
#Nullable WritableMap params) {
reactContext
.getJSModule(DeviceEventManagerModule.RCTDeviceEventEmitter.class)
.emit(eventName, params);
}
WriteableMap and WriteableArray both do not accept objects such as callbacks which made it not possible to request information from the Javascript side. I also attempted to pass in a Promise as opposed to a WriteableMap or WriteableArray and that threw an error. To communicate asynchronously in a synchronous context for android,
I will have to send an event from native to javascript
lock twice to prevent further execution in side native
on my javascript side invoke a method on my native side once viewing the request with the requested data
unlock within the native method invoked by javascript
resume execution since the program has been unlocked
unlock once further after handling whatever needed to be handled synchronously. (Comment if you want my code implementation)
EDIT AGAIN:
The above flow didn't work. I don't have any control over threads in Android since ReactNative always uses the main thread. So if I end up locking the main thread then react-native cannot enter another method to unlock, thus I have deadlock. So not possible to enforce synchronous exchange of data with android.
We use Twilio SDK in our iOS app. It works fine but sometimes didStopListeningForIncomingConnections callback is called with error=31000 ("General error"). After that, the device turns to a strange state: it seems to be online but it's impossible to call it. And it shows "unconnected" state on the device.
So the questions are:
1. What does this 31000 error means?
2. What should we do in such a case? How to reconnect device to Twilio?
Megan from Twilio here.
You can see what an error for Twilio Client means here: https://www.twilio.com/docs/api/client/errors
However, 31000 is a rather vague and less than ideal error message as you describe. In this case, it is likely that the Twilio capability token has probably expired while the application is in the background, and if you merely call the listen method whenever they are receiving the 31000 generic error, it might cause the client SDK to result in a error-retry loop and crash the application eventually.
At the time of your writing with TwilioClient iOS SDK v1.2.5, it is suggested to use the following sample code in your did-stop-listening callback:
- (void)device:(TCDevice*)device didStopListeningForIncomingConnections:(NSError*)error {
if ( [self checkCapabilityTokenStillValid] ) {
// if the token has not yet expired, use the `listen` method of `TCDevice` to resume the listening state
[self.device listen];
}
else {
// restart all over by requesting a new capability token and initialize/update the `TCDevice` instance again
[self login];
}
}
The TwilioClient iOS SDK takes care of dispatching the listen and updateCapabilitiyToken: methods to the current thread for execution, therefore it's safe to call them directly in the didStopListeningForIncomingConnections. The did-stop-listening delegate method is always triggered with dispatch_get_main_queue() of Grand Central Dispatch.
Hope this may help others if they run into the same generic error.
This may or may not be the issue, we have encountered 31000 errors two times in our development and both were a result of generating the JWT on our server api. To be clear the error was a 31000 on the client, but the reason for this was in the construction of the JWT, and the params we wanted twilio to send back to our application.
When passing in an object to allow_client_outgoing or allow_client_incoming the twilio sdk concats this all in their scope attribute in their JWT. It added it to the scope:client:outgoing?appSid= which looks like a query string. That means it has a size limit of 2048. So exceeding this length generates a 31000 error.
In addition adding the objects doesn't seem to always implicitly serialize the object correctly, it introduces characters that can generate errors in their corresponding mobile sdks (but not their web sdk ... weird) so we took care of this by explicitly serializing objects to JSON before they are inserted into the JWT.
I hope both of these examples help you track down the issue.