編輯:關於Android編程
“熱更新”、“熱部署”相信對於混合式開發的童鞋一定不陌生,那麼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原生控件相互之間進行調用的知識就為大家分享完畢,歡迎留言討論,相互學習。
以上就是本文的全部內容,希望本文的內容對大家的學習或者工作能帶來一定的幫助,同時也希望多多支持本站!
去掉ActionBarandroid:theme="@android:style/Theme.Holo.NoActionBar"actionBar =
Hi,大家好,今天給大家分享一下Android中onInterceptTouchEvent與onTouchEvent,,記得樓主以前剛開始找工作的時候,被人問了關於And
Android 開發的程序員開發程序的時候,一定為log而苦惱過吧。Eclipse老是Log找不到,是不是很讓人不爽,雖然Android Studio的Logcat功能很
記得第一次見到ViewPager這個控件,瞬間愛不釋手,做東西的主界面通通ViewPager,以及圖片切換也拋棄了ImageSwitch之類的,開始讓Vie