页面树结构
转至元数据结尾
转至元数据起始

帆软软件推出了html5插件以更好得让报表在移动端展现,本文讲述如何在app中集成html5报表。

html5集成的优势

  1. 安卓/iOS平台可以公用代码,维护方便;
  2. 无需再引入sdk

集成时遇到的问题

目前主要碰到2种问题:超链在新的界面打开的需求;传输数据加密的需求。

  1. App中使用WebView来展示Html5报表,如果单元格/图表上设置了超链,不做任何处理的话会在原webview上打开超链的报表,因为webview可能不是全屏或者本身没有实现前进后退按钮,那么这样的效果会很不理想。更理想的效果应该是新建一个UINavigationController(iOS)或者新开一个Activity(android)来展示超链出来的报表;
  2. 在前端和报表服务器传输数据的过程中,可能一些敏感数据(包括请求的报文和返回的结果)希望在传输的过程中加密;
  3. app有自身的loading样式,希望h5报表中的loading样式和app中能保持一致。

解决方案

问题的解决方案比较类似,都是把事情移交给App去处理。例如超链,需要打开一个超链时,告诉App,需求打开一个超链,那么App就可以自由选择怎么展现;需要向服务器发送数据时,先把数据给App,让App把数据加密了再返回给Html5,再发送到服务器;得到服务器返回的加密结果后,也是先把数据给App,让App解密再给Html5。那么2个问题都涉及到Html5如何App通信,下面详细说明。

IOS部分

  1. 在iOS工程里引入第三方库WebViewJavascriptBridge

定义UIWebView,并设置javascriptBridge,配置javascriptBridge在接收到来自html端的请求后的处理动作。这里的事件名要注意,不能随便写,一定要是我们规定好的字符串。

iOS代码示例
WebViewJavascriptBridge *bridge = [WebViewJavascriptBridge bridgeForWebView:webview]; //定义bridge 
[bridge setWebViewDelegate:self]; //设置代理   
//注册超链的处理函数,注意这里事件名一定要是hyperLinkHandler 
[bridge registerHandler:@"hyperLinkHandler" handler:^(id data, WVJBResponseCallback responseCallback) { 
    [self doHyper:data];//在这里处理超链,data是NSDictionary类型的超链信息,包括name和url 
}];    
//注册数据加密的方法,注意这里事件名一定要是dataEncrypt 
[bridge registerHandler:@"dataEncrypt" handler:^(id data, WVJBResponseCallback responseCallback) { 
    responseCallback([self doEncrypt:data]); //doEncrypt方法为加密方法,通过responseCallback回调,把加密后的结果返回给Html 
}];   
//注册数据解密的方法,注意这里事件名一定要是dataDecrypt 
[bridge registerHandler:@"dataDecrypt" handler:^(id data, WVJBResponseCallback responseCallback) { 
    responseCallback([self doDecrypt:data]); //doDecrypt方法为解密方法,通过responseCallback回调,把解密后的结果返回给Html 
}]; 
//注册显示loading框的方法,注意这里事件名一定要是showLoadingHandler
[bridge registerHandler:@"showLoadingHandler" handler:^(id data, WVJBResponseCallback responseCallback) {
    [self showLoading];
}];
//注册去掉loading框的方法,注意这里事件名一定要是hideLoadingHandler
[bridge registerHandler:@"hideLoadingHandler" handler:^(id data, WVJBResponseCallback responseCallback) {
    [self hideLoading];
}];
[webview loadRequest:request];   
//在这里写收到超链后需要执行的动作,这里在navigationController中重新打开了这个超链。 
- (void) doHyper:(NSDictionary *) hyperLink { 
    NSString *url = [hyperLink objectForKey:@"url"]; 
    NSString *name = [hyperLink objectForKey:@"name"]; 
    Html5ReportWebView *linkView = [[Html5ReportWebView alloc] initWithFrame:CGRectMake(0, 0, self.frame.size.width, 600) andUrl:url]; 
    UIViewController *linkViewController = [[UIViewController alloc] init]; 
    linkViewController.title = name; 
    linkViewController.view.backgroundColor = [UIColor whiteColor]; 
    [linkViewController.view addSubview:linkView]; 
    [someNavigationController pushViewController:linkViewController withAnimate:YES]; 
}
//注意:下面几个方法暂时都需要实现下,如果不需要加解密,直接return原字符串(return str;)即可 。
- (id) doDecrypt:(NSString *) str { 
    //做解密 
    return strAfterDecrypt; 
} 
- (id) doEncrypt:(NSString *) str { 
    //做加密 
    return strAfterEncrypt 
}
- (void) showLoading {
    //show your loading here
    NSLog(@"show");
}
- (void) hideLoading {
    //remove your loading here
    NSLog(@"remove");
}
 

安卓部分

安卓的webView本身是支持addJavascriptInterface方法的,只需要在webview里绑定一个处理通信的类IFJSJavaScriptInterface(注意这里名称一定要是JSBridge,和前端html一致);

定义IFJSJavaScriptInterface里处理超链的方法,名字一定要是handleHyperLink,注意这里需要在暴露给js的方法前加上@JavascriptInterface声明。

安卓Demo
IFJSJavaScriptInterface myJavaScriptInterface = new IFJSJavaScriptInterface(getContext());
addJavascriptInterface(myJavaScriptInterface, "JSBridge"); //名字一定要是JSBridge
@JavascriptInterface
public void handleHyperLink(final String path, final String name) {
  getLoadHandler().post(new Runnable() {
    @Override
    public void run() {
      //这里获取到url后按照需求处理页面,可以新开一个Activity展现
      Intent intent = new Intent(context, WebViewActivity.class);
      intent.putExtra("url",  path); 
      context.startActivity(intent);
    }
  });
}
@JavascriptInterface
public void dataDecrypt(final String data, final String callBack) {
    getLoadHandler().post(new Runnable() {
        @Override
        public void run() {
            //这里做解密的事情,解密完成后,通过html规定的callback回调,把结果传递回去
            webView.loadUrl("javascript:" + callBack + "('" + dataAfterDecrypt + "')");
        }
    });
}
@JavascriptInterface
public void dataEncrypt(final String data, final String callBack) {
    getLoadHandler().post(new Runnable() {
        @Override
        public void run() {
            //这里做加密的事情,加密完成后,通过html规定的callback回调,把结果传递回去
            webView.loadUrl("javascript:" + callBack + "('" + dataAfterEncrypt + "')");
        }
    });
}
@JavascriptInterface
public void handleShowLoading() {
    getLoadHandler().post(new Runnable() {
        @Override
        public void run() {
            //显示loading
        }
    });
}
@JavascriptInterface
public void handleHideLoading() {
    getLoadHandler().post(new Runnable() {
        @Override
        public void run() {
            //去掉loading
        }
    });
}

 







 

 

 




  • 无标签

评论

  1. richie 发表:

    public void dataEncrypt(final String data, final String callBack) {
        getLoadHandler().post(new Runnable() {
            @Override
            public void run() {
                //这里做加密的事情,加密完成后,通过html规定的callback回调,把结果传递回去
                webView.loadUrl("javascript:" + callBack + "('" + dataAfterEncrypt + "')");
            }
        });
    }
    这个方法会有问题,写ReactNative的时候发现用这个方式传图表的JSONObject,前端没法接收,应该是有特殊的字符导致的,这个加密可能会有同样的情况