JS与APP原生控件交互
“热更新”、“热部署”相信对于混合式开发的童鞋一定不陌生,那么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一定要加上去!!!
* 低版本可能没问题,高版本JS铁定调不了Android里面的方法
*/
@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)
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical"
tools:context="com.chinaonenet.mywebview.MainActivity" > <Button
android:id="@+id/button1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentLeft="true"
android:text="无参" /> <Button
android:id="@+id/button2"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignParentRight="true"
android:text="有参" /> <WebView
android:id="@+id/webview"
android:layout_width="wrap_content"
android:layout_height="match_parent"
android:layout_alignParentLeft="true"
android:layout_alignParentRight="true"
android:layout_below="@+id/button2" /> <TextView
android:id="@+id/textView1"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_alignBaseline="@+id/button1"
android:layout_alignBottom="@+id/button1"
android:layout_centerHorizontal="true"
android:text="js与android交互" /> </RelativeLayout>
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; /**
* JS调用android的方法
* @JavascriptInterface仍然必不可少
*/
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页面:
<style>
.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;
}
</style> <div class="main-wrap">
<ul class="postAndroid">
<li onclick="jsCallAndroid('1')">不传参数调用原生控件</li>
<li onclick="jsCallAndroid('2')">传参数调用原生控件</li>
<li onclick="jsCallAndroid('3')">以JSON格式传参数调用原生控件</li>
<li onclick="jsCallAndroid('4')">调用打电话服务</li>
</ul>
</div> <script>
function jsCallAndroid(rel) {
switch(rel){
case "1":
android.callNull();
break;
case "2":
android.callMessage("javaScript操作Android原生");
break;
case "3":
var json = "[{\"name\":\"满艺网\", \"phone\":\"4008366069\"}]";
android.callJson(json);
break;
case "4":
android.callPhone("4008366069");
break;
}
}
function showNoMessage() {
alert("Android无参调用");
}
function showMessage(data) {
alert("Android有参调用-data:" + data);
}
</script>
这里因为需要实现一个拨打电话的功能,所以需要在AndroidManifest.xml文件中添加拨打电话的权限:
<uses-permission android:name="android.permission.CALL_PHONE" />
当然这里加载的页面是本地页面,当加载网络页面时需要添加请求网络权限:
<uses-permission android:name="android.permission.INTERNET" />
好了关于JS与Android原生的控件进行相互调用的知识就介绍完了,最后附上DEML下载地址:http://pan.baidu.com/s/1eR6l7Fk 提取密码:4st0
二、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()
} /**
*加载html页面
*/
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[].toString(), str2: array[].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": , "height": , "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
<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8" />
<title>JSAndIos</title>
</head> <style>
.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;
}
</style> <body bgcolor="#dddd">
<div class="main-wrap">
<ul class="postAndroid">
<li onclick="JS_Swift1()">不传参数调用原生控件(常规方式)</li>
<li onclick="JS_Swift2()">传参数调用原生控件(常规方式)</li>
<li onclick="JS_Swift3()">不传参数调用原生控件,带返回结果处理(模型注入)</li>
<li onclick="JS_Swift4()">传参数调用原生控件(模型注入)</li>
<li onclick="JS_Swift5()">传对象格式参数调用原生控件(模型注入)</li>
<li onclick="JS_Swift6()">传对象格式参数调用原生控件,带返回结果处理(模型注入)</li>
</ul>
</div> <script>
function Swift_JS1() {
alert("Swift调用Js无参方法");
}
function Swift_JS2(name,msg) {
alert("Swift调用Js有参方法,name:"+name+";mes:"+msg);
} function JS_Swift1() {
test1();
}
function JS_Swift2() {
test2('JsCallSwift', 'Js调用Swift方法');
}
function JS_Swift3() {
OCModel.callSystemCamera();
}
//js调用Swift方法,处理返回结果
function jsFunc() {
alert('JS调用Swift方法,无返回值结果处理');
}
function JS_Swift4() {
OCModel.showAlertMsg('js send title', 'js send message');
}
function JS_Swift5() {
OCModel.callWithDict({ 'name': 'testname', 'age': 10, 'height': 170 });
}
function JS_Swift6() {
OCModel.jsCallObjcAndObjcCallJsWithDict({ 'name': 'testname', 'age': 10, 'height': 170 });
}
//注意哦,如果JS写错,可能在OC调用JS方法时,都会出错哦。
function jsParamFunc (argument) {
alert("JS调用Swift方法,有返回值处理结果---name:"+argument['name'] + " age:" + argument['age']);
}
</script>
</body>
</html>
好了,对于JS与Ios原生控件之间进行相互调用的主要内容就分享完毕了,DEML下载地址:链接: https://pan.baidu.com/s/1bpEFzaR 密码: y5ms
到这里关于JS与Android、IOS原生控件相互之间进行调用的知识就为大家分享完毕,欢迎留言讨论,相互学习。
JS与APP原生控件交互的更多相关文章
- JS调用Android、Ios原生控件
在上一篇博客中已经和大家聊了,关于JS与Android.Ios原生控件之间相互通信的详细代码实现,今天我们一起聊一下JS调用Android.Ios通信的相同点和不同点,以便帮助我们在进行混合式开发时, ...
- Js表单验证控件-02 Ajax验证
在<Js表单验证控件(使用方便,无需编码)-01使用说明>中,写了Verify.js验证控件的基本用法,基本可以满足大多数验证需求,如果涉及服务端的验证,则可以通过Ajax. Ajax验证 ...
- IOS版App的控件元素定位
前言 Android版App的控件元素可以通过Android studio自带的工具uiautomatorviewer来协助定位! IOS版App的控件元素可以通过Appium来实现(未实现),或ap ...
- Android音乐、视频类APP常用控件:DraggablePanel(1)
Android音乐.视频类APP常用控件:DraggablePanel(1) Android的音乐视频类APP开发中,常涉及到用户拖曳视频.音乐播放器产生一定交互响应的设计需求,最典型的以You ...
- 论如何在手机端web前端实现自定义原生控件的样式
手机开发webapp的同学一定遇到过这样问题,如何为丑极了的手机元素应用自定义的样式.首先,要弄清楚为什么要定义手机原生控件的样式,就需要看看手机的那些原生框样式的丑陋摸样: android: ios ...
- [js开源组件开发]js多选日期控件
js多选日期控件 详情请见:http://www.lovewebgames.com/jsmodule/calendar.html 它的github地址:https://github.com/tianx ...
- 带着问题写React Native原生控件--Android视频直播控件
最近在做的采用React Native项目有一个需求,视频直播与直播流播放同一个布局中,带着问题去思考如何实现,能更容易找到问题关键点,下面分析这个控件解决方法: 现在条件:视频播放控件(开源的ijk ...
- WPF自定义控件(二)の重写原生控件样式模板
话外篇: 要写一个圆形控件,用Clip,重写模板,去除样式引用圆形图片可以有这三种方式. 开发过程中,我们有时候用WPF原生的控件就能实现自己的需求,但是样式.风格并不能满足我们的需求,那么我们该怎么 ...
- js插件---Bootstrap 树控件
js插件---Bootstrap 树控件 一.总结 一句话总结:可以直接用gojs,或者搜索js,jquery的树控件,或者bootstrap树控件,一大堆 gojs 二.JS组件系列——Bootst ...
随机推荐
- Linux CentOS 配置JDK环境
一.下载JDK 下载JDK的方式有两种: 1.Linux中使用wget下载 1.使用命令安装wget yum install wget 2.下载 wget 'http://download.oracl ...
- Hive on Spark安装配置详解(都是坑啊)
个人主页:http://www.linbingdong.com 简书地址:http://www.jianshu.com/p/a7f75b868568 简介 本文主要记录如何安装配置Hive on Sp ...
- [C#] string 与 String,大 S 与小 S 之间没有什么不可言说的秘密
string 与 String,大 S 与小 S 之间没有什么不可言说的秘密 目录 小写 string 与大写 String 声明与初始化 string string 的不可变性 正则 string ...
- redis集成到Springmvc中及使用实例
redis是现在主流的缓存工具了,因为使用简单.高效且对服务器要求较小,用于大数据量下的缓存 spring也提供了对redis的支持: org.springframework.data.redis.c ...
- PHP好用但又容易忽略的小知识
1.PHP函数之判断函数是否存在 当我们创建了自定义函数,并且了解了可变函数的用法,为了确保程序调用的函数是存在的,经常会先使用function_exists判断一下函数是否存在.同样的method_ ...
- 显示本地openssl支持的加密算法
参考页面: http://www.yuanjiaocheng.net/webapi/parameter-binding.html http://www.yuanjiaocheng.net/webapi ...
- Java中常用集合操作
一.Map 名值对存储的. 常用派生类HashMap类 添加: put(key,value)往集合里添加数据 删除: clear()删除所有 remove(key)清除单个,根据k来找 获取: siz ...
- 页面布局class常见命名规范
头:header 内容:content/container 尾:footer 导航:nav 侧栏:sidebar 栏目:column 页面外围控制整体布局宽度:wrapper 左右中:left rig ...
- CocoaPods的安装、使用、以及遇到的问题
CocoaPods是什么? 当你开发iOS应用时,会经常使用到很多第三方开源类库,比如JSONKit,AFNetWorking等等.可能某个类库又用到其他类库,所以要使用它,必须得另外下载其他类库,而 ...
- 使用Hudson搭建自动构建服务器
环境: ubuntu1404_x64 说明: 使用hudson和git搭建自动构建服务器的简单示例 安装hudson及相关插件 安装hudson 安装命令如下: sudo sh -c "ec ...