How to send data back from iOS to Flutter? - flutter

I am trying to get iOS to send data back to flutter. More specifically the Control Center Media Controls. I am working on a music app and I can get data sent from Flutter to iOS, thus allowing it to be displayed in the Media Controls.
However, how would I get iOS to send data back on its own channel if I were to control play pause next previous? Basically have Flutter listen to iOS sending data.

Assuming that you are using Swift in your plugin (called XXX), you will have a SwiftXXXPlugin class, with a static register method. Move channel to become a static, rather than a local variable of register. Then create some static methods for your iOS to Dart methods and call invokeMethod like this:
channel.invokeMethod("someMethod", arguments: "someValue")
arguments is Any and could be anything that the channel knows how to encode, for example, byte array, String, int, double, etc. It can also encode lists and maps of the basic objects.
At the Dart end, you have XXX.dart. Add a static method called, for example, setHandler, and implement the implementations of the methods. You will need to call setHandler once before using the channel.
static setHandler() {
_channel.setMethodCallHandler(methodCallHandler);
}
static Future<dynamic> methodCallHandler(MethodCall methodCall) async {
switch (methodCall.method) {
case 'someMethod':
print(methodCall.arguments); // prints the argument - "someValue"
return null; // could return a value here
default:
throw PlatformException(code: 'notimpl', message: 'not implemented');
}
}

Related

How to use <Label>k__BackingField: "Aachi" in ionic?

How to use this <Label>k__BackingField: "Aachi" type of data value in ionic?
enter image description here
I am getting this response in the ionic rest API response. API made in ASP .net.
Here is a working example.
export interface YourInterface {
"<Label>k__BackingField": string;
}
let value: YourInterface = { '<Label>k__BackingField': 'Aachi' };
console.log(value['<Label>k__BackingField']); // Outputs 'Aachi'
However, I would recommand renaming/mapping the properties so you can access them with . instead of []. For example, you can have an interface for your raw API response, another interface with 'valid' property names, and a function that converts one to the other, and/or vice versa if needed.

Unable to return value via Platform Channel when using Swift Callback Handlers

I am working with Flutter and Swift. I'm trying to authorize a credit card using the AuthrizeNet SDK, which unfortunately, does not natively support Flutter. To get around this, I created a Platform Channel in my iOS AppDelegate, which I successfully managed receive data in from Flutter. My question now is how can I return that data from inside the callback handler of the authorizing function (from the AuthorizeNet SDK)? When trying to call the Flutter result function, the Swift compiler throws this error: Escaping closure captures non-escaping parameter 'result'. Here's my code:
handler!.getTokenWithRequest(request, successHandler: { (inResponse:AcceptSDKTokenResponse) -> () in
let paymentResponseModel: PaymentResponseModel = PaymentResponseModel.init(
token: inResponse.getOpaqueData().getDataValue(),
resultCode: inResponse.getMessages().getResultCode(),
tokenResultDescription: inResponse.getOpaqueData().getDataDescriptor(),
messageCode: inResponse.getMessages().getMessages()[0].getCode(),
messageText: inResponse.getMessages().getMessages()[0].getText()
)
result(String(data: try! JSONEncoder().encode(paymentResponseModel), encoding: String.Encoding.utf8))
}) { (inError:AcceptSDKErrorResponse) in
let paymentResponseModel: PaymentModelErrorResponse = PaymentModelErrorResponse.init(
code: inError.getMessages().getResultCode(),
message: inError.getMessages().getMessages()[0].getCode(),
details: inError.getMessages().getMessages()[0].getText()
)
result(String(data: try! JSONEncoder().encode(paymentResponseModel), encoding: String.Encoding.utf8))
}
I've tried different way of calling the result function outside of the getTokenWithRequest function, but I couldn't get it to work. I'm fairly new to Swift programming, so I apologize if this question is vague or has a simple solution. Thank you!
The problem is that the successHandler will be called in the future (as a callback), but result must be called immediately and you must return from the method of your code snippet immediately. So, how do you get the success/error response back? You have to make a call from native to Dart when the the token response becomes available. Then, at the Dart end, you'll have to hang about until that response call is made when you can update your app state, and the UI.
It becomes a bi-directional method channel like this:
---token request--->
<---result----------
<---token response--
----result--------->
Neither of the results contains much information, but could be used to convey errors. For example, if the first result comes back false, something went wrong and the Dart end shouldn't expect the token response - it won't happen.

How do I listen for an async response while doing invokeMethod()?

I am working on a small flutter app where I use a native library for some computation. The communication is two-way between dart and java (on android) and uses methodChannels for this.
I call await in_channel.invokeMethod("someJavaMethod") from dart to start the computation. This triggers an init of the native library from Java. The result from this init is coming back as an async JNI call which then triggers out_channel.invokeMethod("someDartMethod").
My plan was to bind the out_channel to a local dart broadcast stream such that I could invoke someJavaMethod and then just await myMethodStream.where((m) => m.method == "someDartMethod")...
Problem is that the "someDartMethod" can come before the "someJavaMethod" call invocation has returned.
combined code example of what I have:
static const MethodChannel _channel_in = const
MethodChannel('native_lib_wrapper_out');
static const MethodChannel _channel_out = const
MethodChannel('native_lib_wrapper_in');
final StreamController<MethodCall> _methodStreamController = new
StreamController.broadcast();
NativeLibWrapper._() {
_channel_in.setMethodCallHandler((MethodCall call) {
_methodStreamController.add(call);
return;
});
}
Future<Map<dynamic,dynamic>> initLib(String id, String filePath)
async {
Map<dynamic,dynamic> ret;
ret = await _channel_out.invokeMethod("initLib", <String,
dynamic> { // data to be passed to the function
'id': id,
'filePath': filePath,
});
print('initLib - invokeMethod done. wait for stream');
if(ret["status"] == 0) {
await NativeLibWrapper.instance._methodStream
.where((m) => m.method == "libInitEnded")
.map((m){
var args = m.arguments;
ret = args;
}).first;
}
return ret;
}
I would have expected the code to get the method call libInitEnded on my stream and then it should return after that point but it continuously hangs in the await on the stream and from the logs it looks like the libInitEnded is called before the print in the middle.
So is there a better way to structure this? it will not be the only methods going back and forth so I hope to get a good stable solution for this.
One channel
You should only need one channel. No need for in and out channels. Both ends may invoke operations on the other over the one channel.
There's only one UI thread
When you call from Dart to Native, the native method is handled by the native UI thread. Unless you are using a thread pool, that means that Dart to Native methods are handled in order. There's no point in not awaiting the answer of every native method. Or, in other words, there's no point in launching two native methods at the same time, since they will be executed consecutively by the single native thread. (Note that you should not perform time-consuming operations on the native thread, as this will interfere with other things it does like gesture detection.) Every Dart to native method should return its result.
Using a thread pool
If the single thread / single method call at a time is unacceptable, consider a thread pool at the native end. Now you can have multiple methods in flight, since there are multiple threads of execution. Now you should design your call/response like you might for communication with a server over a socket. The client gives each request an "invoke id". Each method simply returns a boolean that the request was queued. On completion of the request, the other end invokes the 'done' method, passing the original id and the result. The caller can then match up the response id with the request id and handle the response appropriately (and cancel any timer started to detect timeout). Note that responses can then arrive in any order, but are matched with their request by id.
On Android, you must invoke native to Dart methods on the UIThread. If you are calling the 'done' method from a worker thread you need to post a Runnable lambda to the main looper.

Flash AS3 - Developing for Facebook API locally?

I need to develop a pretty complicated Flash site based on the Facebook API, and if there's a way I can develop locally rather than having to upload it all the time I would be forever grateful.
I saw a post mentioning setting something to localhost but they never specified what exactly ( is it possible to use facebook API locally? )
Much appreciated.
Encapsulation is your friend in this case. When I use external / 3rd party APIs, I like to make a wrapper class of my own for the data. Let's say you only care about 'fbID' and 'userName'. Make a class of your own to hold this data once it is retrieved (private vars with getters, and 1 or more setters). Some skeleton code:
class MyUserClass{
//declare vars here (_fbID, _userName)
public function setData(userID:String, userName:String):void{
//set the values here.
}
//getters here (get fbID, get userName)
}
You can use 2 setter functions if you want to, but the point is that you will be able to call them with any data you want. When your entire application fetches this info from your class, and not the api directly you can work offline. When in offline mode, you can plug in some compatible 'fake' data to see it work.
Now you need to take this to the next level by making a wrapper type for every call you make to facebook. What I mean by this is that since you know what to expect from fb, you can pretend you actually got it, and proceed from there. Asking for a list of friend IDs? make a fake list that is reasonable, and have your application use it. Better still, generate as many fake offline users as you want, and make your server calls delay a random 'lag' time before returning the fake data to the event listener. This will also help test against possible race conditions.
One way to do this is by creating and extending a class to execute the api calls. Enjoy.
import flash.events.EventDispatcher;
import flash.events.Event;
import flash.events.TimerEvent;
import flash.utils.Timer;
class MyApiCaller extends EventDispatcher{
//set up vars to hold call result data
protected var _someData:String;
//make sure to declare some event types for the callbacks
public static const SERVERCALL1_COMPLETE:String = "servercall1_complete";
function MyApiCaller(){
//init things....
}
public function doServerCall1(...args:*):void {
//create the ulrLoader etc...
//set up event listener to onServerCall1Complete
}
public function onServerCall1Complete(event:Event):void {
//parse results, save to vars
//fire event to notify the caller
dispatchEvent(new Event(SERVERCALL1_COMPLETE));
}
//getter to be used when the waiting object gets the SERVERCALL1_COMPLETE event
public function get someData():String {return _someData;}
}
class MyFakeApiCaller extends MyApiCaller{
//set up any additional types (random user data etc..) that would not be found in the base class
//no need to redeclare the event types
function MyFakeApiCaller(){
//init things....
}
override public function doServerCall1(...args:*):void {
//wait a random amount of time via Timer, set up event listener to onServerCall1Complete
}
override public function onServerCall1Complete(event:Event):void {
//event is a TimerEvent in this case
//generate data / choose random data
//save to vars: _someData = ...
//fire event to notify the caller
dispatchEvent(new Event(MyApiCaller.SERVERCALL1_COMPLETE));
}
//getter from base class will be used as usual
}
https://github.com/facebook/php-sdk plus http://www.apachefriends.org/en/xampp.html I believe is your best bet.

Send a empty Message or Notification with MVVM toolkit light

I'm using the MVVM Light Toolkit. I could not find any Ctor of Messenger or Notification class to send a empty message.
ViewModel1:
private int _selectedWeeklyRotation;
public int SelectedWeeklyRotation
{
get { return _selectedWeeklyRotation; }
set
{
if(_selectedWeeklyRotation == value)
return;
_selectedWeeklyRotation = value;
this.OnPropertyChanged("SelectedWeeklyRotation");
if(value > 1)
Messenger.Default.Send();
}
}
ViewModel2:
Ctor:
Messenger.Default.Register(this, CreateAnotherTimeTable);
private void CreateAnotherTimeTable()
{
}
I just need to send a Notification to another ViewModel, no sending of data at all.
Is that possible with MVVM Light Toolkit library?
Unless I'm misunderstanding something, couldn't you accomplish this by creating and sending a custom "signal message" type via the Messenger?
public class WeeklyRotationSignal {}
Messenger.Default.Send(new WeeklyRotationSignal());
Then register to that in another view model:
Messenger.Default.Register<WeeklyRotationSignal>(this, msg => doWork);
You can try sending a simple message with a string tag and receive that message by matching the string tag. Something like this:
Sender portion of the code located possibly in something like ViewModel1.cs
Messenger.Default.Send<string>("Dummy text message", "String_ToHelpMatchTheMsg");
Receiving end portion of the code responding to that message above, possibly located in some other file, something like ViewModel2.cs
...
Messenger.Default.Register<string>(this, "String_ToHelpMatchTheMsg", executeThisFunction);
private void executeThisFunction(string strMsg)
{
//your code would go here to run upon receiving the message
// The following line will display: "Dummy text message"
System.Windows.Browser.HtmlPage.Window.Alert("msg passed: " + strMsg);
}
Please note that you dont have to do anything with the text message that is passed around with the messaging code above. Just one part of the code sending some ping to another part of the code to ask some other section to execute some code. The important string is the one where I used "String_ToHelpMatchTheMsg" because that is the key used to match the sender and the receiver. Almost like creating your own quasi-event, once the Send method runs, the Register method is notified and fire its own function to run also.
I used this with a Close button on a Child Window to close it. The Close button on the View of the Child Window binds to a relay command on its childWindowViewModel. That relay command has the code above to send a message to the ParentViewModel. The Register portion on the ParentViewModel responds to that message by firing a method that closes the ChildWindow which was initially instantied from that parentViewModel.
Once you get more familiar with messaging, there are more attributes that you will be able to use so that the receiver can call back the sender to give a status or some data back. Look for Delegates and lambda function to achieve this.
All this to avoid placing code in the code behind to close the child window! :-)
Use as you see fit.
Cheers.
Mario
There really isn't a way to accomplish this and in someways defies the point of the messenger class. I didn't want to write a your doing it wrong post, but I feel I am stuck. The way the messenger class works is that you have two parties that both subscribe to the same concept, its an observer model. Without that similar concept or message there really isn't a way to tie the two objects together. The generic message whether a simple string or custom message act as the meeting point of the Subscribing and Publishing classes.
If the ViewModel publishing knows the type of ViewModel its trying to Send to it could...
Messenger.Default.Send<Type>(typeof(ViewModelToSendTo);
This would act as a very simple interaction point, you also wouldn't have to create a custom class. Some purist may have an issue with this approach as it couples the publishing class to the subscriber.
I don't think that it is possible and frankly I don't see the point of having that kind of message. You could just as well send a string "SelectedWeeklyRotation". It seems strange to have an empty message that has some kind of meaning as you increase the number of broadcast messages - and receivers in your application.
In the version of MVVM Light that I'm using it is not even possible to send an empty message.
However I did see a method in the ViewModelBase that is :
// Update bindings and broadcast change using GalaSoft.MvvmLight.Messenging
RaisePropertyChanged(MyPropertyPropertyName, oldValue, value, true);
This might be of interest for you.