从ios角度Cordova类图及初始化和互调用流程

1.Cordova类图
这里写图片描述

2.插件管理及插件

控制器基类 CDVViewController,插件管理数据结构

@interface CDVViewController () 
...
@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;
@property (nonatomic, readwrite, strong) NSMutableArray* startupPluginNames;
@property (nonatomic, readwrite, strong) NSDictionary* pluginsMap;

...
@end

控制器基类 CDVViewController,插件管理操作处理
分为初始化注册插件及取插件名,来得到插件,从而调用相应的插件方法,去执行js

@interface CDVViewController : UIViewController <CDVScreenOrientationDelegate>
...
- (id)getCommandInstance:(NSString*)pluginName;
- (void)registerPlugin:(CDVPlugin*)plugin withClassName:(NSString*)className;
- (void)registerPlugin:(CDVPlugin*)plugin withPluginName:(NSString*)pluginName;
...

3.js调用app
刷新webView, 产生回调
- (BOOL)webView:(UIWebView )webView shouldStartLoadWithRequest:(NSURLRequest )request navigationType:(UIWebViewNavigationType)navigationType;
调用 fetchCommandsFromJs 执行 @”cordova.require(‘cordova/exec’).nativeFetchMessages()”获取js返回信息
[CDVCommandQueue fetchCommandsFromJs]

- (BOOL)webView:(UIWebView*)theWebView shouldStartLoadWithRequest:(NSURLRequest*)request navigationType:(UIWebViewNavigationType)navigationType
{
    NSURL* url = [request URL];
    CDVViewController* vc = (CDVViewController*)self.enginePlugin.viewController;

    /*
     * Execute any commands queued with cordova.exec() on the JS side.
     * The part of the URL after gap:// is irrelevant.
     */
    if ([[url scheme] isEqualToString:@"gap"]) {
        [vc.commandQueue fetchCommandsFromJs];
        // The delegate is called asynchronously in this case, so we don't have to use
        // flushCommandQueueWithDelayedJs (setTimeout(0)) as we do with hash changes.
        [vc.commandQueue executePending];
        return NO;
    }
    ...
 }
#0  0x00000001002095f0 in -[CDVCommandQueue enqueueCommandBatch:] 
#1  0x0000000100209c70 in -[CDVCommandQueue fetchCommandsFromJs]_block_invoke 
#2  0x000000010020cfec in -[CDVUIWebViewEngine evaluateJavaScript:completionHandler:] 
#3  0x0000000100209af0 in -[CDVCommandQueue fetchCommandsFromJs] 
#4  0x0000000100208c6c in -[CDVUIWebViewNavigationDelegate webView:shouldStartLoadWithRequest:navigationType:] 
#5  0x00000001001feb7c in -[CDVUIWebViewDelegate webView:shouldStartLoadWithRequest:navigationType:] 
#6  0x0000000196e14d34 in -[UIWebView webView:decidePolicyForNavigationAction:request:frame:decisionListener:] ()
#7  0x0000000190ad0e80 in __invoking___ ()
#8  0x00000001909c62c4 in -[NSInvocation invoke] ()
#9  0x00000001909cae9c in -[NSInvocation invokeWithTarget:] ()
#10 0x0000000196858820 in -[_WebSafeForwarder forwardInvocation:] ()
#11 0x0000000190aced54 in ___forwarding___ ()
#12 0x00000001909cad4c in _CF_forwarding_prep_0 ()
#13 0x0000000190ad0e80 in __invoking___ ()
#14 0x00000001909c62c4 in -[NSInvocation invoke] ()
#15 0x00000001956a0be8 in HandleDelegateSource(void*) ()
#16 0x0000000190a7942c in __CFRUNLOOP_IS_CALLING_OUT_TO_A_SOURCE0_PERFORM_FUNCTION__ ()
#17 0x0000000190a78d9c in __CFRunLoopDoSources0 ()
#18 0x0000000190a769a8 in __CFRunLoopRun ()
#19 0x00000001909a6da4 in CFRunLoopRunSpecific ()
#20 0x0000000192410074 in GSEventRunModal ()
#21 0x0000000196c61058 in UIApplicationMain ()
#22 0x00000001000ff544 in main

再根据js返回信息,CDVCommandQueue动态创建本地插件,识别方法,进行调用

- (void)fetchCommandsFromJs
{
    __weak CDVCommandQueue* weakSelf = self;
    NSString* js = @"cordova.require('cordova/exec').nativeFetchMessages()";

    [_viewController.webViewEngine evaluateJavaScript:js
                                    completionHandler:^(id obj, NSError* error) {
        if ((error == nil) && [obj isKindOfClass:[NSString class]]) {
            NSString* queuedCommandsJSON = (NSString*)obj;
            CDV_EXEC_LOG(@"Exec: Flushed JS->native queue (hadCommands=%d).", [queuedCommandsJSON length] > 0);
            [weakSelf enqueueCommandBatch:queuedCommandsJSON];
            // this has to be called here now, because fetchCommandsFromJs is now async (previously: synchronous)
            [self executePending];
        }
    }];
}

- (void)executePending
{
    // Make us re-entrant-safe.
    if (_startExecutionTime > 0) {
        return;
    }
    @try {
        _startExecutionTime = [NSDate timeIntervalSinceReferenceDate];

        while ([_queue count] > 0) {
            NSMutableArray* commandBatchHolder = _queue[0];
            NSMutableArray* commandBatch = nil;
            @synchronized(commandBatchHolder) {
                // If the next-up command is still being decoded, wait for it.
                if ([commandBatchHolder count] == 0) {
                    break;
                }
                commandBatch = commandBatchHolder[0];
            }

            while ([commandBatch count] > 0) {
                @autoreleasepool {
                    // Execute the commands one-at-a-time.
                    NSArray* jsonEntry = [commandBatch cdv_dequeue];
                    if ([commandBatch count] == 0) {
                        [_queue removeObjectAtIndex:0];
                    }
                    CDVInvokedUrlCommand* command = [CDVInvokedUrlCommand commandFromJson:jsonEntry];
                    CDV_EXEC_LOG(@"Exec(%@): Calling %@.%@", command.callbackId, command.className, command.methodName);

                    if (![self execute:command]) {
#ifdef DEBUG
                            NSString* commandJson = [jsonEntry cdv_JSONString];
                            static NSUInteger maxLogLength = 1024;
                            NSString* commandString = ([commandJson length] > maxLogLength) ?
                                [NSString stringWithFormat : @"%@[...]", [commandJson substringToIndex:maxLogLength]] :
                                commandJson;

                            DLog(@"FAILED pluginJSON = %@", commandString);
#endif
                    }
                }

                // Yield if we're taking too long.
                if (([_queue count] > 0) && ([NSDate timeIntervalSinceReferenceDate] - _startExecutionTime > MAX_EXECUTION_TIME)) {
                    [self performSelector:@selector(executePending) withObject:nil afterDelay:0];
                    return;
                }
            }
        }
    } @finally
    {
        _startExecutionTime = 0;
    }
}

4, app 调用js
被动调用过程
调用增加热点[cordova_plug_krpanoedit addhotspot:]本质是上执行js @”cordova.require(‘cordova/exec’).nativeCallback(‘cordova_plug_krpanoedit1493891283’,1,{“y”:”26.3451”,”title”:”美景”,”name”:”hostspot0”,”x”:”120.073”,”scale”:”0.4”},0, 1)”

#0  0x000000010020cfc4 in -[CDVUIWebViewEngine evaluateJavaScript:completionHandler:]
#1  0x00000001002001a0 in -[CDVCommandDelegateImpl evalJsHelper2:]
#2  0x000000010020054c in -[CDVCommandDelegateImpl evalJsHelper:] 
#3  0x0000000100200960 in -[CDVCommandDelegateImpl sendPluginResult:callbackId:]
#4  0x0000000100115448 in -[cordova_plug_krpanoedit addhotspot:] 

主动调用,在应用程序中增加按钮,用户操作按钮来激活相应的javascript操作的情况

在CDVCommandDelegateImpl.h中增加下面的公开方法,相当于是直接调用webView的文件来执行javascript,不经过Cordova框架去查找插件,由插件再来调用javascript函数。
- (void)evalJsHelper:(NSString*)js;

@interface CDVCommandDelegateImpl : NSObject <CDVCommandDelegate>{
    @private
    __weak CDVViewController* _viewController;
    NSRegularExpression* _callbackIdPattern;
    @protected
    __weak CDVCommandQueue* _commandQueue;
    BOOL _delayResponses;
}
- (id)initWithViewController:(CDVViewController*)viewController;
- (void)flushCommandQueueWithDelayedJs;

- (void)evalJsHelper:(NSString*)js;

@end

调用示例

//控制器
@implementation MainViewController
...
- (void)viewDidLoad
{
    [super viewDidLoad];
    UIButton *btn;
    btn = [[UIButton alloc] init];
    btn.frame = CGRectMake(100, 100, 80, 30);
    [btn setTitle:@"hotspot" forState:UIControlStateNormal  ];
    [self.view addSubview:btn];
    [btn addTarget:self action:@selector(action:) forControlEvents:UIControlEventTouchUpInside];
    // Do any additional setup after loading the view from its nib.
}
- (void) action:(UIButton*)sender{
    cordova_plug_krpanoedit *kr;
    kr = [self getCommandInstance:@"cordova_plug_krpanoedit"];
    if(kr){
        [kr appAddhotspot:nil];
    }
}
...
@end

//插件
@implementation cordova_plug_krpanoedit
...
- (void) appAddhotspot:(NSDictionary*)dic  {
    [self.commandDelegate evalJs:@"hotspot();"];
}
...
@end

app主动调用,目前想到的是这样的一个方法,如果有更好的办法,可以留言,我补充上去。

5.别人的梳理文章

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值