worklight 6.0 adapter native ios to hybrids application - ibm-mobilefirst

I can able to call worklight 6.0 adapter invoke in IOS native code (using Objective-C) but i can not read adapter JSON response using cordova plugin from my hybrids application.
// invoke the adapter
MyConnectListener *connectListener = [[MyConnectListener alloc] initWithController:self];
[[WLClient sharedInstance] wlConnectWithDelegate:connectListener];
// calling the adapter using objective-c
WLProcedureInvocationData *myInvocationData = [[WLProcedureInvocationData alloc] initWithAdapterName:#"HTTP_WS_ADPTR" procedureName:#"getBalance"];
MyInvokeListener *invokeListener = [[MyInvokeListener alloc] initWithController: self];
[[WLClient sharedInstance] invokeProcedure:myInvocationData withDelegate:invokeListener];
CDVPluginResult *pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:responseString];
[self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
// hybrids application call the native code
cordova.exec(sayHelloSuccess, sayHelloFailure, "HelloWorldPlugin", "sayHello", [name]);
above the cordova.exec success and failed method is not return the value.
but i can not able to parse the value from CDVPluginResult method. Anybody please advice me. how can i read the adapter for IOS native from hybrids application.

Several things to note:
You are using Worklight 6.0.0.x. In Worklight 6.0.0.x there is no proper session sharing between web and native views. Meaning, if you will for example call the WL.Client.connect() method in the web view and then do a connect() and adapter invocation in the native view - these calls will not share the same session which can lead to race condition errors, inability to share state between the views and other unexpected events. Not recommended.
If this is the approach you're looking to implement in your Hybrid application it is therefore highly recommended that you will upgrade to either MobileFirst (previous known as "Worklight") v6.3 or v7.0 where session sharing between web and native views is now available out-of-the-box.
Although you might just want to opt to call the adapter from the JS code...
To get this to work as-is in your supplied project, you can change the implementation based on the below.
Note that the implementation below was based on MFP 7.0, as such the adapter invocation code will not work in your 6.0.0.0x codebase. You will need to alter it based on your own code in v6.0.0.x:
sayHello.h
#import <Foundation/Foundation.h>
#import <Cordova/CDV.h>
#import "WLClient.h"
#import "WLDelegate.h"
#interface SayHelloPlugin : CDVPlugin
- (void)sayHello:(CDVInvokedUrlCommand*)command;
- (void)callResult:(NSString*)response;
#end
sayHello.m
#import "SayHelloPlugin.h"
#import "MyConnectListener.h"
CDVInvokedUrlCommand *tempCommand;
#implementation SayHelloPlugin
- (void)sayHello:(CDVInvokedUrlCommand*)command {
MyConnectListener *connectListener = [[MyConnectListener alloc] init:self];
[[WLClient sharedInstance] wlConnectWithDelegate:connectListener];
tempCommand = command;
}
-(void)callResult:(NSString*)response{
CDVPluginResult *pluginResult =
[CDVPluginResult resultWithStatus:CDVCommandStatus_OK messageAsString:response];
[self.commandDelegate sendPluginResult:pluginResult callbackId:tempCommand.callbackId];
}
#end
MyConnectListener.h
#import <Foundation/Foundation.h>
#import "WLClient.h"
#import "WLDelegate.h"
#import "SayHelloPlugin.h"
#interface MyConnectListener : NSObject <WLDelegate> {
#private
SayHelloPlugin *sh;
}
- (id)init: (SayHelloPlugin *)sayHello;
#end
MyConnctListener.m
The responseText line is commented out because the data retrieved from the adapter was too large I suppose, so it's best to return only what you really need and not all of it.
#import "MyConnectListener.h"
#import "WLResourceRequest.h"
NSString *resultText;
NSString *request;
#implementation MyConnectListener
- (id)init: (SayHelloPlugin *) sayHello{
if ( self = [super init] )
{
sh = sayHello;
}
return self;
}
-(void)onSuccess:(WLResponse *)response{
NSURL* url = [NSURL URLWithString:#"/adapters/testAdapter/getStories"];
WLResourceRequest* request = [WLResourceRequest requestWithURL:url method:WLHttpMethodGet];
[request setQueryParameterValue:#"['technology']" forName:#"params"];
[request sendWithCompletionHandler:^(WLResponse *response, NSError *error) {
if(error != nil){
resultText = #"Invocation failure: ";
resultText = [resultText stringByAppendingString: error.description];
[sh callResult:resultText];
}
else{
resultText = #"Invocation success. ";
//resultText = [resultText stringByAppendingString:response.responseText];
[sh callResult:resultText];
}
}];
}
-(void)onFailure:(WLFailResponse *)response{
resultText = #"Connection failure: ";
resultText = [resultText stringByAppendingString:[response errorMsg]];
NSLog(#"***** failure response: %#", resultText);
[sh callResult:resultText];
}
#end

Related

MLKit object detector is crashing in MLKObjectDetectorOptions

I am trying to fetch object frames from given image using MKLKIT. But my code is getting crashed
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
#import <Foundation/Foundation.h>
#import <MLKitObjectDetection/MLKitObjectDetection.h>
#import <MLKitObjectDetectionCommon/MLKObjectDetector.h>
#import <MLKitObjectDetection/MLKObjectDetectorOptions.h>
#import <MLKitObjectDetectionCommon/MLKObject.h>
#import <MLKitVision/MLKVisionImage.h>
#import "MLKitObjectDetection.h"
#implementation MLObjectDetection
- (NSMutableArray*)detectFrame:(UIImage*)image{
NSMutableArray *frames = [NSMutableArray new];
// Multiple object detection in static images
MLKObjectDetectorOptions *options = [[MLKObjectDetectorOptions alloc] init];
options.detectorMode = MLKObjectDetectorModeSingleImage;
options.shouldEnableMultipleObjects = YES;
MLKObjectDetector *objectDetector = [MLKObjectDetector objectDetectorWithOptions:options];
MLKVisionImage *visionImage = [[MLKVisionImage alloc] initWithImage:image];
visionImage.orientation = image.imageOrientation;
NSError *error;
NSArray *objects = [objectDetector resultsInImage:visionImage error:&error];
if (error == nil) {
return frames;
}
if (objects.count == 0) {
// No objects detected.
}
for (MLKObject *object in objects) {
[frames addObject:[NSValue valueWithCGRect:object.frame]];
}
//TODO release memory
return frames;
}
#end
When your code crash, did you try to run your code inside Xcode and look into the console in the debug area to check what error message was printed out there? Usually that will give you some clue as to what led to the crash.
Based on your code, are you calling the detectFrame: method from the main UI thread? The synchronous MLKObjectDetector#resultsInImage:error: should never be called from the main UI thread. This is documented in its API reference. You can check out ML Kit's quickstart sample app here. It shows how to call both the synchronous MLKObjectDetector#resultsInImage:error: API and the asynchronous MLKObjectDetector#processImage:completion: API.

How to debug communication between XPC service and client app in OSX

I'm trying to write a simple pair of "client app" & "XPC service". I was able to launch xpc service from client (i.e I can see service running in the Activity monitor processes list), but when I try to send any request, that has a response block, I get an error: "Couldn’t communicate with a helper application."
The worst thing here is that error doesn't give me any info about what went wrong. And I'm also unable to debug the service properly. As I understand, the correct way to do this is to attach a debugger to process (Debug->Attach to process, also see here). I have both client and service projects in a single workspace.
When I run client from xcode and try to attach debugger to launched service, that ends with a "Could not attach to pid : X" error.
If I archive the client app run it from app file and then try to attach debugger to service the result is the same.
The only way to record something from the service I could imagine is to write a logger class, that would write data to some file. Haven't tried this approach yet, however that looks insane to me.
So my question is:
a) How to find out what went wrong, when receiving such non-informative response like: "Couldn’t communicate with a helper application"?
b) And also, what's the correct way to debug the xpc service in the first place? The link above is 5 years old from now, however I can see that some people were saying that "attach to debugger" wasn't working.
The code itself is fairly simple:
XPC service, listener implementation:
#import "ProcessorListener.h"
#implementation ProcessorListener
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection
{
[newConnection setExportedInterface: [NSXPCInterface interfaceWithProtocol:#protocol(TestServiceProtocol)]];
[newConnection setExportedObject: self];
self.xpcConnection = newConnection;
newConnection.remoteObjectInterface = [NSXPCInterface interfaceWithProtocol: #protocol(Progress)];
// connections start suspended by default, so resume and start receiving them
[newConnection resume];
return YES;
}
- (void) sendMessageWithResponse:(NSString *)receivedString reply:(void (^)(NSString *))reply
{
reply = #"This is a response";
}
- (void) sendMessageWithNoResponse:(NSString *)mString
{
// no response here, dummy method
NSLog(#"%#", mString);
}
And the main file for service:
#import <Foundation/Foundation.h>
#import "TestService.h"
#interface ServiceDelegate : NSObject <NSXPCListenerDelegate>
#end
#implementation ServiceDelegate
- (BOOL)listener:(NSXPCListener *)listener shouldAcceptNewConnection:(NSXPCConnection *)newConnection {
// This method is where the NSXPCListener configures, accepts, and resumes a new incoming NSXPCConnection.
// Configure the connection.
// First, set the interface that the exported object implements.
newConnection.exportedInterface = [NSXPCInterface interfaceWithProtocol:#protocol(TestServiceProtocol)];
// Next, set the object that the connection exports. All messages sent on the connection to this service will be sent to the exported object to handle. The connection retains the exported object.
TestService *exportedObject = [TestService new];
newConnection.exportedObject = exportedObject;
// Resuming the connection allows the system to deliver more incoming messages.
[newConnection resume];
// Returning YES from this method tells the system that you have accepted this connection. If you want to reject the connection for some reason, call -invalidate on the connection and return NO.
return YES;
}
#end
int main(int argc, const char *argv[])
{
// [NSThread sleepForTimeInterval:10.0];
// Create the delegate for the service.
ServiceDelegate *delegate = [ServiceDelegate new];
// Set up the one NSXPCListener for this service. It will handle all incoming connections.
NSXPCListener *listener = [NSXPCListener serviceListener];
listener.delegate = delegate;
// Resuming the serviceListener starts this service. This method does not return.
[listener resume];
return 0;
}
For client app, the UI contains a bunch of buttons:
- (IBAction)buttonSendMessageTap:(id)sender {
if ([daemonController running])
{
[self executeRemoteProcessWithName:#"NoResponse"];
}
else
{
[[self.labelMessageResult cell] setTitle: #"Error"];
}
}
- (IBAction)buttonSendMessage2:(id)sender {
if ([daemonController running])
{
[self executeRemoteProcessWithName:#"WithResponse"];
}
else
{
[[self.labelMessageResult cell] setTitle: #"Error"];
}
}
- (void) executeRemoteProcessWithName: (NSString*) processName
{
// Create connection
NSXPCInterface * myCookieInterface = [NSXPCInterface interfaceWithProtocol: #protocol(Processor)];
NSXPCConnection * connection = [[NSXPCConnection alloc] initWithServiceName: #"bunldeID"]; // there's a correct bundle id there, really
[connection setRemoteObjectInterface: myCookieInterface];
connection.exportedInterface = [NSXPCInterface interfaceWithProtocol:#protocol(Progress)];
connection.exportedObject = self;
[connection resume];
// NOTE that this error handling code is not called, when debugging client, i.e connection seems to be established
id<Processor> theProcessor = [connection remoteObjectProxyWithErrorHandler:^(NSError *err)
{
NSAlert *alert = [[NSAlert alloc] init];
[alert addButtonWithTitle: #"OK"];
[alert setMessageText: err.localizedDescription];
[alert setAlertStyle: NSAlertStyleWarning];
[alert performSelectorOnMainThread: #selector(runModal) withObject: nil waitUntilDone: YES];
}];
if ([processName containsString:#"NoResponse"])
{
[theProcessor sendMessageWithNoResponse:#"message"];
}
else if ([processName containsString:#"WithResponse"])
{
[theProcessor sendMessageWithResponse:#"message" reply:^(NSString* replyString)
{
[[self.labelMessageResult cell] setTitle: replyString];
}];
}
}
Jonathan Levin's XPoCe tool is helpful when you can't attach a debugger.
You can add logging NSLog() or fprintf(stderr,...) to your service and clients, specifically around the status codes. You just have to specify the path of the file to write stdout and stderr. <key>StandardErrorPath</key> <string>/tmp/mystderr.log</string>
There's a section on Debugging Daemons at this article on objc.io .

How to pull data point from Firebase using Obj-C?

I'm saving a users zip code to the Firebase database and want to query that database on app launch to see if the user has input their zip code already or if they're a brand new user.
I've posted my code before. I pulled the sample code from the Firebase docs, but it seems that my app is never even running the following code to get the value
[[[_ref child:#"user"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {...
What am I missing out on?
#import "FollowingVC.h"
#import <FirebaseDatabase/FirebaseDatabase.h>
#import Firebase;
#interface FollowingVC ()
#property NSString *uid;
#property FIRDatabaseReference *ref;
#property NSString *zipcode;
#end
#implementation FollowingVC
- (void)viewDidLoad {
[super viewDidLoad];
[self createAuthorizedUser];
[self checkForZipCode];
}
-(void)createAuthorizedUser
{
[[FIRAuth auth]
signInAnonymouslyWithCompletion:^(FIRUser *_Nullable user, NSError *_Nullable error) {
if (!error) {
self.uid = user.uid;
self.ref=[[FIRDatabase database]reference];
}
}];
}
-(void)checkForZipCode
{
NSString *userID = [FIRAuth auth].currentUser.uid;
[[[_ref child:#"user"] child:userID] observeSingleEventOfType:FIRDataEventTypeValue withBlock:^(FIRDataSnapshot * _Nonnull snapshot) {
// Get user value
self.zipcode = snapshot.value[#"zip code"];
NSLog(#"It worked: %#", self.zipcode);
// ...
} withCancelBlock:^(NSError * _Nonnull error) {
NSLog(#"%#", error.localizedDescription);
}];
}
#end
Firebase is asynronous and you need to allow time for events to complete before moving on in the app.
In this case, you should call [self checkForZipCode] inside the sign-in block after self.uid is populated.
Otherwise you run the risk of the checkForZipCode function running before the self.uid is populated.
Let Firebase control the flow of the app - and don't try to use Firebase synchronously as it will get you into trouble due to internet lag etc.

Using Objective-c hidden api (iphone)

I'm trying to use this guthub According to this link for using objective c private api but the documentation is pretty lousily.
I copied past the exemple code to my xcode but I'm getting compilation error.
NSBundle *b = [NSBundle bundleWithPath:#"/System/Library/PrivateFrameworks/TelephonyUI.framework"];
BOOL success = [b load];
Class SKTelephonyController = NSClassFromString(#"SKTelephonyController");
//this line cussing the error
**id tc = [SKTelephonyController sharedInstance];**
NSLog(#"-- myPhoneNumber: %#", [tc myPhoneNumber]);
NSLog(#"-- imei: %#", [tc imei]);
error:
No known instance method for selector 'myPhoneNumber'
Can someone please have a guide or something to get started.
Oh, I know my app will not pass apple validation, I dont need there validation its an internal app.
thanks.
First of all, the example doesn't say to load SKTelephonyController, it says to load GAIA.framework
Second is that SKTelephonyController and GAIA are not available for iOS7 (they was working on iOS 6)
Here is example, how you need to dummy declare an interface, and make calls.
#interface SKTelephonyController : NSObject
+ (id)sharedInstance;
+ (NSString *)myPhoneNumber;
+ (NSString *)imei;
#end
#implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
NSBundle *b = [NSBundle bundleWithPath:#"/System/Library/PrivateFrameworks/GAIA.framework"];
BOOL success = [b load];
if (!success) {
NSLog(#"Can't load bundle");
return;
}
NSLog(#"-- imei: %#", [[SKTelephonyController sharedInstance] imei]);
}

asyncudpsocket does not send UDP as expected

I have XCODE 3.1.4 running ona mini MAC 10.5.8 and Simulator 3.1
I want to send a short UDP string for some remote control and have made the following code
Basicly it does compile and run in the simulator ... but it nevers send any UDP to the target. I hope someone can give me a clue why it does not work
My .H code
#import <UIKit/UIKit.h>
#import "AsyncUdpSocket.h"
#import "AsyncSocket.h"
#interface ChangeLabelViewController : UIViewController {
IBOutlet UILabel *label ;
AsyncUdpSocket *socket;
}
-(IBAction) ChangeLabel;
-(IBAction) ResetLabel;
#end
My .m code
#import "ChangeLabelViewController.h"
#implementation ChangeLabelViewController
-(IBAction) ChangeLabel
{
label.text = #"Hello";
}
-(IBAction) ResetLabel
{
label.text = #"Empty";
NSLog(#"%s", __PRETTY_FUNCTION__);
NSString * string = #"Testing iPhone";
NSString * address = #"192.168.1.11";
UInt16 port = 1234;
NSData * data = [string dataUsingEncoding: NSUTF8StringEncoding];
if ([socket sendData:data toHost:address port:port withTimeout:- 1 tag:1]) label.text = #"Send";
// if ([socket sendData:data toHost:address port:port withTimeout:-1 tag:1] == YES) label.text = #"Yes";
// if ([socket sendData:data toHost:address port:port withTimeout:-1 tag:1] == NO) then label.text = #"No";
;
}
#end
Had to init the socket
under - (void) vievDidLoad
socket = [[AsyncUdpSocket alloc] initWithDelegate:self];
Then it worked as expected :-)
If you are staring from a brand new project you will also need to do the following:
1. add CFNetwork to your frameworks in the project
2. add the cocaasyncsockets files to your project
Instructions are here: http://code.google.com/p/cocoaasyncsocket/wiki/iPhone
Pay attention to the instructions on how to add CFNetwork, it is not shown in the list of available options.
Hint: you will need to use the finder to select a path, I am a mac novice so it took me a while to figure out that I had to use Go/Go To Folder....