全网整合营销服务商

电脑端+手机端+微信端=数据同步管理

免费咨询热线:400-708-3566

详解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/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()
 }
 /**
 *加载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[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

<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/1gfJXr83

到这里关于JS与Android、IOS原生控件相互之间进行调用的知识就为大家分享完毕,欢迎留言讨论,相互学习。

以上就是本文的全部内容,希望本文的内容对大家的学习或者工作能带来一定的帮助,同时也希望多多支持!


# js  # 控件  # 交互  # android中webview控件和javascript交互实例  # ActiveX控件与Javascript之间的交互示例  # 加载  # 的是  # 好了  # 下载地址  # 要在  # 不传  # 提示信息  # 便可  # 看一下  # 大家分享  # 就为  # 拨打电话  # 返回值  # 不可能  # 都在  # 都要  # 只需  # 能在  # 第二个  # 相互之间 


相关文章: 上海网站制作开发公司,上海买房比较好的网站有哪些?  网站制作培训多少钱一个月,网站优化seo培训课程有哪些?  营销式网站制作方案,销售哪个网站招聘效果最好?  相亲简历制作网站推荐大全,新相亲大会主持人小萍萍资料?  网站制作的步骤包括,正确网址格式怎么写?  如何设置并定期更换建站之星安全管理员密码?  海南网站制作公司有哪些,海口网是哪家的?  制作无缝贴图网站有哪些,3dmax无缝贴图怎么调?  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  用v-html解决Vue.js渲染中html标签不被解析的问题  西安市网站制作公司,哪个相亲网站比较好?西安比较好的相亲网站?  建站之星如何实现网站加密操作?  如何确保西部建站助手FTP传输的安全性?  可靠的网站设计制作软件,做网站设计需要什么样的电脑配置?  学校建站服务器如何选型才能满足性能需求?  桂林网站制作公司有哪些,桂林马拉松怎么报名?  Dapper的Execute方法的返回值是什么意思 Dapper Execute返回值详解  网站视频制作书签怎么做,ie浏览器怎么将网站固定在书签工具栏?  如何通过免费商城建站系统源码自定义网站主题与功能?  C#怎么创建控制台应用 C# Console App项目创建方法  如何通过.red域名打造高辨识度品牌网站?  如何选择高效响应式自助建站源码系统?  实现点击下箭头变上箭头来回切换的两种方法【推荐】  外贸公司网站制作哪家好,maersk船公司官网?  如何实现建站之星域名转发设置?  济南专业网站制作公司,济南信息工程学校怎么样?  如何优化Golang Web性能_Golang HTTP服务器性能提升方法  开封网站制作公司,网络用语开封是什么意思?  如何配置IIS站点权限与局域网访问?  制作网站建设的公司有哪些,网站建设比较好的公司都有哪些?  成都网站制作报价公司,成都工业用气开户费用?  常州自助建站费用包含哪些项目?  如何快速搭建高效香港服务器网站?  建站之星代理平台如何选择最佳方案?  成都网站制作价格表,现在成都广电的单独网络宽带有多少的,资费是什么情况呢?  广州美橙建站如何快速搭建多端合一网站?  如何通过远程VPS快速搭建个人网站?  简单实现Android文件上传  建站上传速度慢?如何优化加速网站加载效率?  建站主机是否等同于虚拟主机?  弹幕视频网站制作教程下载,弹幕视频网站是什么意思?  招商网站制作流程,网站招商广告语?  建站之星如何快速更换网站模板?  北京制作网站的公司,北京铁路集团官方网站?  高端云建站费用究竟需要多少预算?  哈尔滨网站建设策划,哈尔滨电工证查询网站?  小程序网站制作需要准备什么资料,如何制作小程序?  唐山网站制作公司有哪些,唐山找工作哪个网站最靠谱?  专业网站建设制作报价,网页设计制作要考什么证?  如何快速生成专业多端适配建站电话? 

您的项目需求

*请认真填写需求信息,我们会在24小时内与您取得联系。