iOS应用中的JS交互

来源:互联网 发布:网络直播策划方案脚本 编辑:程序博客网 时间:2024/06/05 11:11

刚进公司的时候发现公司要做的是hybrid应用,当时对JS交互没有一点概念。自己研究了好几天,最后决定用JavaScriptObjectiveCDelegate协议来实现。现在记录实现过程。

首先,新建一个模型类JsObjCModel,其中包含了需要调用的方法。JavaScriptObjectiveCDelegate协议中声明了两个方法,这两个方法可以在服务端直接调用。其中一个是获取设备ID,服务端调用后直接得到返回值。另一个是注册方法,用来实现获取用户位置(因为获取用户位置需要回调方法)。服务端调用registerMethod方法,传过来一个数组作为参数,我们通过NSArray *args = [JSContext currentArguments];获取到。跟写后台的同事沟通,第一个参数表示回调函数的uuid,第二个参数代表需要实现的方法。知道第二个参数是@"device.getGps",因此调用- (void)getGps,得到结果后拼接数据,调用后台的方法window.IOS.Handle.exec()传回结果。

#import <Foundation/Foundation.h>#import <UIKit/UIKit.h>#import <JavaScriptCore/JavaScriptCore.h>@class HHYWebViewController;@protocol JavaScriptObjectiveCDelegate <JSExport>- (NSString *)getDeviceID;    //获取设备id,直接调用的方法- (void)registerMethod;//注册方法,用于带参数或者有回调的调用@end@interface JsObjCModel : NSObject<JavaScriptObjectiveCDelegate>@property (nonatomic, weak) JSContext *jsContext;@property (nonatomic, weak) UIWebView *webView;@property (nonatomic, weak)  HHYWebViewController *viewController;@end

#import "JsObjCModel.h"#import "HHYWebViewController.h"@interface JsObjCModel ()<CLLocationManagerDelegate>@end@implementation JsObjCModel{    CLLocationManager *locationManager;    NSString *backGpsUuid;}- (void)registerMethod{    NSArray *args = [JSContext currentArguments];    for (id obj in args) {        NSLog(@"html传过来的参数:::%@",obj);    }    if ([args count]>1) {        if ([[args[1] toString] isEqualToString:@"device.getGps"]) {            [self performSelector:@selector(getGps) withObject:nil afterDelay:0];            backGpsUuid = [args[0] toString];        }    }}- (HHYWebViewController *)viewController{    if (!_viewController) {        _viewController = [[HHYWebViewController alloc] init];    }    return _viewController;}-(void)setLocation:(CLLocationCoordinate2D)location{    NSLog(@"设置值成功");    _location=location;    }#pragma mark -获取设备id-(NSString *)getDeviceID{    NSUUID *deviceUID = [UIDevice currentDevice].identifierForVendor;    NSString *uuuid=deviceUID.UUIDString;    return uuuid;}#pragma mark -获取定位信息- (void)getGps{    locationManager = [[CLLocationManager alloc] init];    locationManager.delegate = self;    locationManager.desiredAccuracy = kCLLocationAccuracyBest;    locationManager.distanceFilter = 5.0f;    if (SYSTEM_VERSION >= 8.0) {        [locationManager requestWhenInUseAuthorization];    }        [locationManager startUpdatingLocation];    [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(gotGpsString:) name:@"GotGpsString" object:nil];}- (void)locationManager:(CLLocationManager *)manager didUpdateLocations:(NSArray<CLLocation *> *)locations{    if ([locations count]) {        CLLocation *latestLocation = [locations lastObject];        NSString *longitude = [NSString stringWithFormat:@"%f",latestLocation.coordinate.longitude];        NSString *latitude = [NSString stringWithFormat:@"%f",latestLocation.coordinate.latitude];        NSDictionary *arg = @{@"longitude":longitude,                              @"latitude":latitude};        NSArray *argArray = @[arg];        NSDictionary *backDic = @{@"succ" : @YES,                                  @"callback" : backGpsUuid,                                  @"arguments" : argArray};        NSData *data = [NSJSONSerialization dataWithJSONObject:backDic options:NSJSONWritingPrettyPrinted error:nil];        NSString *gpsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];                        [[NSNotificationCenter defaultCenter]postNotificationName:@"GotGpsString" object:nil userInfo:@{@"gpsString":gpsString}];        [locationManager stopUpdatingLocation];    }}- (void)locationManager:(CLLocationManager *)manager didFailWithError:(NSError *)error{    NSLog(@"定位失败,请检查设置");    NSDictionary *backDic = @{@"succ" : @YES,                              @"callback" : backGpsUuid,                              @"arguments" : @[@"定位失败"]};    NSData *data = [NSJSONSerialization dataWithJSONObject:backDic options:NSJSONWritingPrettyPrinted error:nil];    NSString *gpsString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];    [[NSNotificationCenter defaultCenter]postNotificationName:@"GotGpsString" object:nil userInfo:@{@"gpsString":gpsString}];}- (void)gotGpsString:(NSNotification *)notificat{    NSString *gpsString = [notificat userInfo][@"gpsString"];    NSString *jsStr = [NSString stringWithFormat:@"window.IOS.Handle.exec(%@)",gpsString];    [self.viewController.webView stringByEvaluatingJavaScriptFromString:jsStr];    NSLog(@"gpsString===%@",gpsString);    [[NSNotificationCenter defaultCenter] removeObserver:self name:@"GotGpsString" object:nil];}

然后是新建包含UIWebView的视图控制器,在实现文件中注入交互对象。

#import <UIKit/UIKit.h>#import <JavaScriptCore/JavaScriptCore.h>#import "JsObjCModel.h"@interface HHYWebViewController : UIViewController@property (nonatomic,strong)JsObjCModel *model;@property (nonatomic, strong) UIWebView *webView;@end
注入交互对象的时机很重要,一开始我只在- (void)webViewDidFinishLoad:(UIWebView *)webView中注入,发现有时候后台在调用交互方法时页面还没有加载完,就调用不到。因此我在此处使用了https://github.com/TomSwift/UIWebView-TS_JavaScriptContext。

在m文件中导入#import "UIWebView+TS_JavaScriptContext.h",并遵守TSWebViewDelegate。在代理方法中注入交互对象,这样就能在每次创建JSContext的时候都注入,避免调用不到的情况。

- (void)webView:(UIWebView *)webView didCreateJavaScriptContext:(JSContext *)ctx{    ctx[@"JsBridge"] = self.model;    ctx[@"viewController"] = self;    self.model.jsContext = ctx;    self.model.webView = self.webView;    self.model.viewController = self;    ctx.exceptionHandler = ^(JSContext *context, JSValue *exceptionValue) {        context.exception = exceptionValue;        NSLog(@"异常信息:%@", exceptionValue);    };}

参考:

http://www.jianshu.com/p/939db6215436

http://blog.csdn.net/lwjok2007/article/details/47058795





0 0
原创粉丝点击