從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.別人的梳理文章

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章