“热更新”、“热部署”相信对于混合式开发的童鞋一定不陌生,那么APP怎么避免每次升级都要在APP应用商店发布呢?这里就用到了混合式开发的概念,对于电商网站尤其显得重要,不可能每次发布一个活动,都要发布一个现版本,当然这样对于Android还算可以,但是对于Ios呢?苹果应用商店每次审核的时间基本都在1~2周,这对于一个促销活动来说审核时间实在太长。而混合式开发正好可以解决这个问题,基本的原理时,通过原生控件实现APP的主体结构,借助H5开发对应的页面,这样每次发布活动,只需要在服务器端,将活动发布,便可以达到所有安装用户不升级便可查阅最新活动的效果。今天就为大家分享一下,如何实现Javascript与APP原生控件交互。
一、首先为大家介绍的是JS与Android交互,首先让大家看一下Android工程的目录结构:
JSObject.java文件封装了JS调用Android原生控件的方法;MainActivity.java是调用WebView控件实现网页页面加载,以及进行控件调用JS方法的封装;test.html是我们加载的HTML页面。接下来我们具体看一下实现:
MainActivity.java
package com.chinaonenet.mywebview;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.view.View.OnClickListener;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.widget.Button;
@SuppressLint("SetJavascriptEnabled")
public class MainActivity extends Activity {
private Button button1,button2;
private WebView mWebView;
private MyWebViewClient WVClient;
private WebSettings webSettings;
private MyWebChromeClient chromeClient;
//封装接收js调用Android的方法类
private JSObject jsobject;
//异步请求
private Handler mHandler = new Handler();
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
init();
initView();
setButton();
}
private void setButton() {
//无参调用
button1.setonClickListener(new onClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
mWebView.loadUrl("javascript:showNoMessage()");
}
});
}
});
//有参调用
button2.setonClickListener(new onClickListener() {
@Override
public void onClick(View v) {
mHandler.post(new Runnable() {
@Override
public void run() {
mWebView.loadUrl("javascript:showMessage('顺带给JS传个参数')");
}
});
}
});
}
private void init() {
mWebView = (WebView) findViewById(R.id.webview);
button1 = (Button)findViewById(R.id.button1);
button2 = (Button)findViewById(R.id.button2);
WVClient = new MyWebViewClient();
chromeClient = new MyWebChromeClient();
jsobject = new JSObject(MainActivity.this);
}
private void initView() {
webSettings = mWebView.getSettings();
webSettings.setJavascriptEnabled(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setSavePassword(false);
//支持多种分辨率,需要js网页支持
webSettings.setUserAgentString("mac os");
webSettings.setDefaultTextEncodingName("utf-8");
//显示本地js网页
mWebView.loadUrl("file:///android_asset/test.html");
mWebView.setWebViewClient(WVClient);
mWebView.setWebChromeClient(chromeClient);
//注意第二个参数android,这个是JS网页调用Android方法的一个类似ID的东西
mWebView.addJavascriptInterface(jsobject, "android");
}
}
页面的配置文件(activity_main.xml)
JSObject.java
package com.chinaonenet.mywebview;
import org.json.JSONArray;
import org.json.JSONException;
import android.content.Context;
import android.content.Intent;
import android.net.Uri;
import android.webkit.JavascriptInterface;
import android.widget.Toast;
public class JSObject {
private Context context;
public JSObject(Context context){
this.context = context;
}
//js调用无参方法
@JavascriptInterface
public void callNull(){
Toast.makeText(context, "JsCallAndroid", Toast.LENGTH_SHORT).show();
}
//js调用有参方法
@JavascriptInterface
public void callMessage(String data){
Toast.makeText(context, data, Toast.LENGTH_SHORT).show();
}
//js调用有参方法,参数类型:JSON
@JavascriptInterface
public void callJson(String data) throws JSONException{
JSonArray jsonArray = new JSonArray(data);
Toast.makeText(context, jsonArray.toString(), Toast.LENGTH_SHORT).show();
}
//js调用有参方法,参数类型:JSON,获取电话号码拨打
@JavascriptInterface
public void callPhone(String data){
context.startActivity(new Intent(Intent.ACTION_CALL, Uri.parse("tel:" + data)));
}
}
加载的HTML页面:
.main-wrap ul { width: 100%; display: inline-block; padding-top: 20px; } .main-wrap ul li { float: left; width: 100%; height: 40px; line-height: 40px; font-size: 14px; margin-bottom: 20px; background-color: #00D000; color: #fff; text-align: center; cursor: pointer; } .main-wrap ul li:active { opacity: 0.8; }
- 不传参数调用原生控件
- 传参数调用原生控件
- 以JSON格式传参数调用原生控件
- 调用打电话服务
这里因为需要实现一个拨打电话的功能,所以需要在AndroidManifest.xml文件中添加拨打电话的权限:
当然这里加载的页面是本地页面,当加载网络页面时需要添加请求网络权限:
好了关于JS与Android原生的控件进行相互调用的知识就介绍完了,最后附上DEML下载地址:http://pan.baidu.com/s/1eSza8Pc
二、JS与IOS原生交互,这里的开发语言选用的是Swift语言,版本是2.2。首先上工程目录结构:
ViewController.swift
import UIKit
import JavascriptCore
class ViewController: UIViewController {
var context = JSContext()
var jsContext: JSContext?
@IBOutlet weak var webView: UIWebView!
override func viewDidLoad() {
super.viewDidLoad()
webView.delegate = self//初始化webView
loadJS()
}
func loadJS() {
let str = NSBundle.mainBundle().pathForResource("test", ofType: "html")
let request = NSURLRequest(URL: NSURL(string: str!)!)
webView.loadRequest(request)
}
//Swift 调用JS 方法 (无参数)
@IBAction func swift_js_pargram(sender: AnyObject) {
self.context.evaluatescript("Swift_JS1()")
//self.webView.stringByevaluatingJavascriptFromString("Swift_JS1()") //此方法也可行
}
//Swift 调用JS 方法 (有参数)
@IBAction func swift_js_nopargam(sender: AnyObject) {
self.context.evaluatescript("Swift_JS2('Ios' ,'Swift')")
//self.webView.stringByevaluatingJavascriptFromString("Swift_JS2('oc','swift')") //此方法也可行
}
//js调用Swift方法(无参)
func menthod1() {
print("JS调用了无参数swift方法")
let title = "操作提示";
let msg = "JS调用了无参数swift方法";
//创建提示信息
let alert = UIalertController(title: title, message: msg, preferredStyle: .alert)
//确定按钮
alert.addAction(UIalertAction(title: "ok", style: .Default, handler: nil))
//显示提示框
self.presentViewController(alert, animated: true, completion: nil)
}
//js调用Swift方法(有参数)
func menthod2(str1: String, str2: String) {
print("JS调用了有参数swift方法:参数为(str1),(str2)")
//创建提示信息
let alert = UIalertController(title: str1, message: str2, preferredStyle: .alert)
//确定按钮
alert.addAction(UIalertAction(title: "ok", style: .Default, handler: nil))
//显示提示框
self.presentViewController(alert, animated: true, completion: nil)
}
func webView(webView: UIWebView, didFailLoadWithError error: NSError) {
print(error)
}
}
//js调用Swift方法注入
extension ViewController: UIWebViewDelegate {
func webView(webView: UIWebView, shouldStartLoadWithRequest request: NSURLRequest, navigationType: UIWebViewNavigationType) -> Bool {
let str = NSBundle.mainBundle().pathForResource("test", ofType: "html")
let request = NSURLRequest(URL: NSURL(string: str!)!)
let connecntion = NSURLConnection(request: request, delegate: self)
connecntion?.start()
return true
}
func webViewDidStartLoad(webView: UIWebView) {
print("webViewDidStartLoad----")
}
func webViewDidFinishLoad(webView: UIWebView) {
self.context = webView.valueForKeyPath("documentView.webView.mainframe.javascriptContext") as! JSContext
//JS调用了无参数swift方法---menthod1
let temp1: @convention(block) () ->() = {
self.menthod1()
}
//forKeyedSubscript:参数为JS调用方法名
self.context.setObject(unsafeBitCast(temp1, AnyObject.self), forKeyedSubscript: "test1")
//JS调用了有参数swift方法---menthod2
let temp2: @convention(block) () ->() = {
let array = JSContext.currentArguments()//这里接到的array中的内容是JSValue类型
for object in array {
print("参数:" + object.toString())
}
self.menthod2(array[0].toString(), str2: array[1].toString())
}
//forKeyedSubscript:参数为JS调用方法名
self.context.setObject(unsafeBitCast(temp2, AnyObject.self), forKeyedSubscript: "test2")
//模型注入的方法
let model = JSObjCModel()
model.controller = self
model.jsContext = context
self.jsContext = context
//这一步是将OCModel这个模型注入到JS中,JS就可以通过OCModel调用我们公暴露的方法了。
self.jsContext?.setObject(model, forKeyedSubscript: "OCModel")
let url = NSBundle.mainBundle().URLForResource("test", withExtension: "html")
self.jsContext?.evaluatescript(try? String(contentsOfURL: url!, encoding: NSUTF8StringEncoding));
self.jsContext?.exceptionHandler = {
(context, exception) in
print("exception @", exception)
}
}
}
@objc protocol JavascriptSwiftDelegate: JSExport {
func callSystemCamera()
func showalert(title: String, msg: String)
func callWithDict(dict: [String: AnyObject])
func jsCallObjcAndObjcCallJsWithDict(dict: [String: AnyObject])
}
//js调用Swift模型方法
@objc class JSObjCModel: NSObject, JavascriptSwiftDelegate {
weak var controller: UIViewController?
weak var jsContext: JSContext?
//JS无参调用Swift方法并返回处理结果
func callSystemCamera() {
print("js call objc method: callSystemCamera");
let jsFunc = self.jsContext?.objectForKeyedSubscript("jsFunc");
jsFunc?.callWithArguments([]);
}
//JS有参调用Swift方法
func showalert(title: String, msg: String) {
print("js call objc method: showalert, title: %@", title, " msg: %@", msg)
dispatch_async(dispatch_get_main_queue()) { () -> Void in
let alert = UIalertController(title: title, message: msg, preferredStyle: .alert)
alert.addAction(UIalertAction(title: "ok", style: .Default, handler: nil))
self.controller?.presentViewController(alert, animated: true, completion: nil)
}
}
//JS有参调用Swift方法
func callWithDict(dict: [String : AnyObject]) {
print("js call objc method: callWithDict, args: %@", dict)
let alert = UIalertController(title: "消息提示", message: "查看控制台打印信息", preferredStyle: .alert)
alert.addAction(UIalertAction(title: "ok", style: .Default, handler: nil))
self.controller?.presentViewController(alert, animated: true, completion: nil)
}
//JS有参调用Swift方法并返回处理结果
func jsCallObjcAndObjcCallJsWithDict(dict: [String : AnyObject]) {
print("js call objc method: jsCallObjcAndObjcCallJsWithDict, args: %@", dict)
let jsParamFunc = self.jsContext?.objectForKeyedSubscript("jsParamFunc");
let dict = NSDictionary(dictionary: ["age": 2, "height": 178, "name": "满艺网"])
jsParamFunc?.callWithArguments([dict])
}
}
extension ViewController: NSURLConnectionDelegate,NSURLConnectionDataDelegate {
func connection(connection: NSURLConnection, didReceiveData data: NSData) {
print("didReceiveData(data)")
}
func connection(connection: NSURLConnection, willSendRequest request: NSURLRequest, redirectResponse response: NSURLResponse?) -> NSURLRequest? {
print("request:(request)response:(response)")
return request
}
func connection(connection: NSURLConnection, didFailWithError error: NSError) {
}
}
//MARK: - allowsAnyHTTPSCertificateForHost
extension NSURLRequest {
static func allowsAnyHTTPSCertificateForHost(host: String) -> Bool {
return true
}
}
test.html
JSAndIos .main-wrap ul { width: 100%; display: inline-block; padding-top: 20px; } .main-wrap ul li { float: left; width: 100%; height: 40px; line-height: 40px; font-size: 14px; margin-bottom: 20px; background-color: #00D000; color: #fff; text-align: center; cursor: pointer; } .main-wrap ul li:active { opacity: 0.8; }
- 不传参数调用原生控件(常规方式)
- 传参数调用原生控件(常规方式)
- 不传参数调用原生控件,带返回结果处理(模型注入)
- 传参数调用原生控件(模型注入)
- 传对象格式参数调用原生控件(模型注入)
- 传对象格式参数调用原生控件,带返回结果处理(模型注入)
好了,对于JS与Ios原生控件之间进行相互调用的主要内容就分享完毕了,DEML下载地址:https://pan.baidu.com/s/1gfJXr83
到这里关于JS与Android、IOS原生控件相互之间进行调用的知识就为大家分享完毕,欢迎留言讨论,相互学习。
以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持考高分网!



