PhoneGap / Cordova 回调错误 - 在 PhoneGap 中未执行 RestKit 完成功能

Posted

技术标签:

【中文标题】PhoneGap / Cordova 回调错误 - 在 PhoneGap 中未执行 RestKit 完成功能【英文标题】:PhoneGap / Cordova Callback Bug - RestKit Completion Functions Not Executing in PhoneGap 【发布时间】:2012-08-23 21:15:21 【问题描述】:

如果从 RestKit 回调中调用,PhoneGap 回调似乎不起作用。我们已经通过删除 RestKit 调用验证了我们的 PhoneGap 回调逻辑工作正常(加上我们所有其他 PhoneGap 插件回调工作正常)。在下面的代码中,loader.onDidLoadResponse 在 RestKit 调用完成后执行,然而,即使通过 PhoneGap / Cordova 回调行执行,javascript 中相应的完成例程也不会执行。就好像回调消失了。我们是否在上下文或我们编写 RestKit 或 PhoneGap 异步逻辑的方式上做错了什么?

任何帮助将不胜感激。

-(void)GetRestJson:(NSMutableArray*)arguments withDict:(NSMutableDictionary*)options

    NSString* callbackID = [arguments pop];
    NSLog(@"%@",callbackID);
    NSString* url = [arguments objectAtIndex:0];
    NSString* sublocation = [arguments objectAtIndex:1];
    NSDictionary * args = [NSDictionary dictionaryWithObjectsAndKeys:
                           callbackID, @"callBackID",
                           self, @"thisObject",                           
                           nil];
    RKClient* client = [RKClient clientWithBaseURL:[RKURL URLWithString:url]];

// <---- RESTKIT CALL MADE (WORKS)
    [client get:sublocation usingBlock:^(RKRequest* loader)
     
         loader.onDidLoadResponse = ^(RKResponse *response)     // <---- RESTKIT COMPLETION CALLED (WORKS)
         
             NSString* result = [response bodyAsString];
             NSString * callbackID = [args objectForKey:@"callBackID"];
             id callingObject = [args objectForKey:@"thisObject"];

             CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                                               messageAsString: [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
             [callingObject writeJavascript: [pluginResult toSuccessCallbackString:callbackID]];  // <---- PHONEGAP CALLBACK MADE (BROKEN --- DOESN'T ARRIVE BACK ON JS CALLBACK)

         ;

         loader.onDidFailLoadWithError = ^(NSError *error)
         
             NSString* result = [error description];
             NSLog(@"Loaded payload: %@", result);
             NSString * callbackID = [args objectForKey:@"callBackID"];
             id callingObject = [args objectForKey:@"thisObject"];
             CDVPluginResult* pluginResult = [CDVPluginResult resultWithStatus:CDVCommandStatus_OK
                                                               messageAsString: [result stringByAddingPercentEscapesUsingEncoding:NSUTF8StringEncoding]];
             [callingObject writeJavascript: [pluginResult toErrorCallbackString:callbackID]];
         ;
     ];

【问题讨论】:

【参考方案1】:

两个不明显的错误阻止了 RestKit 完成函数的执行:

问题 #1 - PhoneGap 2.0.0 / Cordova 2.0.0 在异步回调逻辑中存在错误

PhoneGap 回调逻辑有一个错误,它可以触发来自不同上下文的不相关调用的回调函数。当从 Javascript 进行调用时,PhoneGap 会生成一个新的 callbackId,将其添加到 cordova.callbacks 数组中,并将其传递给本机代码。一段时间后,当原生代码完成请求时,它会注入 javascript 来调用 callbackSuccess 或 callbackError 函数。相应的回调处理程序从 cordova.callbacks 数组中查找回调属性并执行原始调用者的完成函数。问题是每个页面,或页面的重新加载,将 callbackId 计数器重置为零,并且新调用最终会重用相同的 callbackId,即使本机代码尚未完成先前的请求。这可能发生在新页面加载或锚标记中的空 href 重新加载时。从 page1.html 调用本机代码可能会触发 page2.html 上的完成例程,因为本机代码在桥的另一侧没有更改的上下文。

解决方案: 将递增的 callbackId 替换为唯一标识符,以确保仅调用调用者的完成逻辑。我已经使用 Pseudo-GUID 生成器完成了这项工作。修复概述如下:

在 cordova.2.0.0.js 和 cordova.ios.js 中替换这条线

callbackId = service + cordova.callbackId++;    // BUG: incrementing callbackId's can call unrelated callback logic

用这条线

callbackId = service + ":" + 'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g, function(c) var r = Math.random()*16|0,v=c=='x'?r:r&0x3|0x8;return v.toString(16);); // Generate unique callbackID with Pseudo-GUID

问题 #2 - 由于锚点为空的 href 导致页面重新加载

调用页面使用带有空 href="" 的锚标记,这会导致当前页面重新加载并 $(document).ready 再次触发。重新加载会重置 cordova.callbackId 计数器和 cordova.callbacks 数组。新触发的 .ready 函数对本机代码进行新的调用,并重用相同的 callbackId,它们已在使用中,但仍从本机代码中的前一个页面实例挂起。当 RestKit 调用完成时,PhoneGap/Cordova 将 callbackId 触发到现在重复的无关逻辑条目。

解决方案: 如上所述修复 callbackId 逻辑可防止执行不相关的回调逻辑。解决方案的第二部分是从锚标记中删除 href 或仅在 div 元素中使用 onclick 以防止页面重新加载或导航到重用 callbackIds 的新页面。

【讨论】:

作为 Cordova 2.0 缺陷提交 - 在此处跟踪:Track it Here

以上是关于PhoneGap / Cordova 回调错误 - 在 PhoneGap 中未执行 RestKit 完成功能的主要内容,如果未能解决你的问题,请参考以下文章

ATTN PhoneGap/Cordova 项目贡献者:以 2 种不同方式调用 deviceready 回调的问题

PhoneGap 插件:从未调用过 AudioEncode 成功回调

Phonegap 通信原理

CompileXIB 中的 Phonegap (Cordova) 错误

Cordova/PhoneGap:安装 calendarPlugin 后出现链接器错误

PhoneGap/Cordova WebStorm Ubuntu - 错误