iOS应用中的JS交互

刚进公司的时候发现公司要做的是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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值