1

I've built a Cordova application and I'm just adding some native functionality in xcode. I want to intercept the urls from my application as is demonstrated here:

How to invoke Objective C method from Javascript and send back data to Javascript in iOS?

So in my HTML I have included a link

index.html

<a class="MyButton" id="id" href="req://ResultA">Item A</a>

Then I just have a really basic header file which inherits from the UIViewController

MyViewController.h

#import <UIKit/UIKit.h>
#import <Cordova/CDVViewController.h>

@interface MyViewController : UIViewController

@end

And then in my MyViewController.m file all I want to do is to interpret the url from my link. I want to achieve something like below.

MyViewController.m

- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];

    CDVViewController* StorySelectCDVViewController = [CDVViewController new];
    StorySelectCDVViewController.view.frame = self.view.frame;
    [self.view addSubview:StorySelectCDVViewController.view];
}

...

-(bool)webView:(UIWebView *)webView shouldStartLoadWithRequest:(NSURLRequest *)request navigationType:(UIWebViewNavigationType)navigationType
{
    if ([[url scheme] isEqualToString:@"req"])
        //Store ResultA as a variable for later use.
}

but for the CDVViewController. As well as this I've been reading that it's bad practice to try to use the ViewController as a delegate for the CDVViewController with regards to this method since it messes with the API calls?


Alternatively I could also try to copy the MainViewController provided by the Cordova application and create a ViewController which inherits CDVViewController...

MyViewController.h

#import <Cordova/CDVViewController.h>
#import <Cordova/CDVCommandDelegateImpl.h>
#import <Cordova/CDVCommandQueue.h>

@interface MyViewController : CDVViewController

@end

@interface MyCommandDelegate : CDVCommandDelegateImpl
@end

@interface MyCommandQueue : CDVCommandQueue
@end

MyViewController.m

#import "MyViewController.h"

@implementation MyViewController

- (id)initWithNibName:(NSString*)nibNameOrNil bundle:(NSBundle*)nibBundleOrNil
{
    self = [super initWithNibName:nibNameOrNil bundle:nibBundleOrNil];
    if (self) {
        // Uncomment to override the CDVCommandDelegateImpl used
        // _commandDelegate = [[MyCommandDelegate alloc] initWithViewController:self];
        // Uncomment to override the CDVCommandQueue used
        // _commandQueue = [[MyCommandQueue alloc] initWithViewController:self];
    }
    return self;
}

- (id)init
{
    self = [super init];
    if (self) {
        // Uncomment to override the CDVCommandDelegateImpl used
        // _commandDelegate = [[MyCommandDelegate alloc] initWithViewController:self];
        // Uncomment to override the CDVCommandQueue used
        // _commandQueue = [[MyCommandQueue alloc] initWithViewController:self];
    }
    return self;
}


@end

@implementation MyCommandDelegate

#pragma mark CDVCommandDelegate implementation

- (id)getCommandInstance:(NSString*)className
{
    return [super getCommandInstance:className];
}

- (NSString*)pathForResource:(NSString*)resourcepath
{
    return [super pathForResource:resourcepath];
}

@end

@implementation MyCommandQueue

- (BOOL)execute:(CDVInvokedUrlCommand*)command
{
    return [super execute:command];
}

@end

However I'm not sure how to modify this appropriately to tap into the URL Command appropriately. Does anybody have any ideas?

Community
  • 1
  • 1
AlecGamble
  • 109
  • 6
  • When you have to communicate to native code from HTML/javascript you can use this approach but you will have to mess around with the native project created by Cordova and create conditional blocks in the WebView delegate method (bad). I usually prefer to create a native plugin for those scenarios, f or me is much cleaner and easier. You can google for iOS plugin examples and have a look [here](https://cordova.apache.org/docs/en/5.1.1/guide/platforms/ios/plugin.html). – Fabio Felici May 09 '16 at 16:10
  • Thank you so much for your response! that's incredibly helpful! I'm still a little confused as to the structure of creating my own plugin though. I have a fresh Cordova project. Would you be able to tell me what components I need and where they should go? I'm not sure about things like `using the plugin.xml file to inject this markup automatically`. I know I need the CDVPlugin files in the xcodeproject plugins folder, I can configure the config.xml file in the ios platform I just need to know where stuff goes outside of that. Thank you! – AlecGamble May 10 '16 at 09:37

1 Answers1

1

This is what you need to create an iOS plugin:

  • plugin.xml
  • src/ios/YourPluginName.h
  • src/ios/YourPluginName.m
  • www/YourPluginName.js

plugin.xml

<?xml version="1.0" encoding="UTF-8"?>
<plugin xmlns="http://apache.org/cordova/ns/plugins/1.0"
           id="yourpluginid"
      version="1.0.0">
    <name>YourPluginName</name>
    <description>Your Plugin Description</description>
    <license>Apache 2.0</license>
    <js-module src="www/YourPluginName.js" name="YourPluginName">
        <clobbers target="YourPluginName" />
    </js-module>
    <platform name="ios">
        <config-file target="config.xml" parent="/*">
            <feature name="YourPluginName">
                <param name="ios-package" value="YourPluginName"/>
            </feature>
        </config-file>
        <header-file src="src/ios/YourPluginName.h" />
        <source-file src="src/ios/YourPluginName.m" />
    </platform>
</plugin>

src/ios/YourPluginName.h

#import <Foundation/Foundation.h>
#import <Cordova/CDV.h>

@interface YourPluginName : CDVPlugin

- (void)pluginMethodName:(CDVInvokedUrlCommand*)command;

@end

src/ios/YourPluginName.m

#import "YourPluginName.h"

@implementation YourPluginName

- (void)pluginMethodName:(CDVInvokedUrlCommand*)command {
    CDVPluginResult* pluginResult = nil;
    //Get param
    NSString *param = [command.arguments objectAtIndex:0];
    //Do something
    pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK];
    [self.commandDelegate sendPluginResult:pluginResult callbackId:command.callbackId];
}

www/YourPluginName.js

var exec = require('cordova/exec');

var YourPluginName = {
    pluginMethodName:function(param, successCallback, errorCallback) {
        exec(successCallback, errorCallback, "YourPluginName", "pluginMethodName", [param]);
    }
};

module.exports = YourPluginName;

Put each file inside a folder and then type from the root folder of your cordova project:

cordova plugin add pluginfolderpath

Then from your javascript (after the onDeviceReady event) you can do:

YourPluginName.pluginMethodName("param", function(){}, function(){});
Fabio Felici
  • 2,841
  • 15
  • 21