當下移動開發主要實現方式有傳統的Native以及新的混合開發想Rect.js,nodejs這些前段框架,其本質要麼是原生控件來實現UI,要麼html來實現UI。Xamarin其實也只是取巧而已,目的在於方便net開發者再學習java以及蛋疼的oc和不成熟的swift,好了廢話很少說了。javascript
gis做爲軟件領域基礎性存在,比之傳統表格列表等圖形化展示數據優點。在app中因爲國內國外牆緣由通常都使用三方api,百度,高德,騰訊之類,其中高德天然是國內作得最專業的在線地圖服務商,他們的api都很簡單,所要注意一點就是座標系,由於座標系的緣由經常標註一些地物要素對不上號。像傳統老牌arcgis在移動領域其實也只是刷存在感。在xamarin中要開發地圖應用天然的不得不使用三方,緣由嘛android綁定了谷歌,ios嘛綁定了高德地圖api功能又不夠強大。怎麼辦的用高德,百度,騰訊,那麼問題來了,xamarin使用三方庫,這地方很是蛋疼,緣由嘛xamarin其實將原生庫元素據提取出來與c#語法映射,什麼jar,.a ,.framework用很不成熟的sharpie工具反射,其實在這個過程當中千絲萬縷的牽涉到原生的oc姿式,不得不說很是蛋疼。即便你可以看懂官方英文,demo各類類型對應,問題仍是會很多,不是缺個類就是函數簽名對不上號,要麼就是即便能is某個類型但as卻編譯不過。html
問題天然是要解決的,隨着h5的完善webview不失爲更好一種辦法,說白了就是把網頁嵌入到頁面中用c#與js交互,在這裏以百度js api爲例。java
在xamarin.android中因爲4.4版本如下瀏覽器內核存在天生渲染慢加載慢等不足,在xamarin.ios自8.0後加強優化wkwebview控件。node
android實現代碼android
1 using System; 2 using Android.Net.Http; 3 using Android.OS; 4 using Android.Webkit; 5 using MobileOperation.Droid.Web; 6 using MobileOperation.Views; 7 using Xamarin.Forms; 8 using Xamarin.Forms.Platform.Android; 9 using View = Android.Views.View; 10 using WebView = Android.Webkit.WebView; 11
12 [assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))] 13 namespace MobileOperation.Droid.Web 14 { 15 public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>, IDownloadListener, View.IOnLongClickListener 16 { 17 const string JavaScriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}"; 18
19
20
21 protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e) 22 { 23 base.OnElementChanged(e); 24
25 if (Control == null) 26 { 27 var webView = new Android.Webkit.WebView(Forms.Context); 28 webView.Settings.JavaScriptEnabled = true; 29 webView.SetDownloadListener(this); 30 SetNativeControl(webView); 31 } 32 if (e.OldElement != null) 33 { 34 Control.RemoveJavascriptInterface("jsBridge"); 35 var hybridWebView = e.OldElement as HybridWebView; 36
37 } 38 if (e.NewElement != null) 39 { 40
41 Control.AddJavascriptInterface(new JSBridge(this), "jsBridge"); 42 //Control.LoadUrl(string.Format("file:///android_asset/Web/{0}", Element.Uri));
43 InjectJS(JavaScriptFunction); 44
45
46 Control.Settings.JavaScriptEnabled = true; 47 Control.SetWebChromeClient(new GeoWebChromeClient()); 48 Control.SetWebViewClient(new MyWebViewClient()); 49 Control.SetNetworkAvailable(true); 50 Control.Settings.SetGeolocationEnabled(true); 51 Control.Settings.JavaScriptCanOpenWindowsAutomatically = (true); 52
53 Control.Settings.SetAppCacheEnabled(true); 54 Control.Settings.AllowFileAccess=(true); 55 Control.Settings.DomStorageEnabled=(true); 56 Control.Settings.SetSupportZoom(false); 57 Control.Settings.SetSupportMultipleWindows(false); 58 Control.Settings.BuiltInZoomControls=(false); 59 Control.Settings.SetRenderPriority(WebSettings.RenderPriority.High); 60
61 Control.SetOnLongClickListener(this); 62 Control.ClearCache(true); 63 if ((int)Build.VERSION.SdkInt >= 19) 64 { 65 Control.Settings.LoadsImagesAutomatically=(true); 66 } 67 else
68 { 69 Control.Settings.LoadsImagesAutomatically=(false); 70 } 71
72
73
74 var hybirdWebView = e.NewElement; 75 hybirdWebView.RegisterInvokeJsFunctionAgent((s, action) =>
76 { 77 string jsInvokeStr = string.Format("javascript: {0}", s); 78
79 // 若是android運行版本高於4.4則調用該版本及其以上所支持的函數
80 if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) 81 { 82 Control.EvaluateJavascript(jsInvokeStr, new ValueCallback(Control)); 83 } 84 else
85 { 86 // todo 此處調用自己並不支持有返回值
87 Control.LoadUrl(jsInvokeStr); 88 } 89
90 //res http://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/
91
92 // todo 目前在android還沒法實現有返回值
93 if (action != null) 94 { 95 action(string.Empty); 96 } 97 }); 98 //Control.LoadUrl(string.Format("http://map.baidu.com/mobile/webapp/index.html"));
99 Control.LoadUrl(string.Format("http://192.168.50.148/baidu/index.html")); 100 //Control.LoadUrl(string.Format("http://192.168.50.254")); 101 //Control.LoadUrl(string.Format("http://map.baidu.com/mobile/webapp/search/search/qt=s&wd=atm&c=75&searchFlag=bigBox&version=5&exptype=dep&src_from=webapp_all_bigBox&src=0&nb_x=11577553.94&nb_y=3541989.14¢er_rank=1/vt=map"));
102
103
104 } 105 } 106
107 void InjectJS(string script) 108 { 109 if (Control != null) 110 { 111 Control.LoadUrl(string.Format("javascript: {0}", script)); 112 } 113 } 114
115 public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength) 116 { 117
118 } 119
120 public bool OnLongClick(View v) 121 { 122 return true; 123
124 } 125 } 126
127 public class GeoWebChromeClient : WebChromeClient 128 { 129 public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback) 130 { 131 //容許經過權限詢問訪問
132 callback.Invoke(origin, true, false); 133 } 134
135
136
137 } 138
139
140 public class MyWebViewClient : WebViewClient 141 { 142 public override bool ShouldOverrideUrlLoading(WebView view, string url) 143 { 144 view.LoadUrl(url); 145 return true; 146 } 147 public override void OnPageFinished(WebView view, String url) 148 { 149 if (!view.Settings.LoadsImagesAutomatically) 150 { 151 view.Settings.LoadsImagesAutomatically=(true); 152 } 153 } 154
155
156 public override void OnReceivedSslError(WebView view, SslErrorHandler handler, SslError error) 157 { 158 handler.Proceed(); 159 } 160
161 public override void OnReceivedError(WebView view, ClientError errorCode, string description, string failingUrl) 162 { 163 base.OnReceivedError(view, errorCode, description, failingUrl); 164
165
166 } 167
168
169
170
171 } 172
173 public class ValueCallback : IValueCallback 174 { 175
176 private Android.Webkit.WebView webView; 177
178 public ValueCallback(Android.Webkit.WebView wbView) 179 { 180 webView = wbView; 181 } 182
183 public void OnReceiveValue(Java.Lang.Object value) 184 { 185
186 } 187
188 public System.IntPtr Handle 189 { 190 get { return new IntPtr(); } 191 } 192
193 public void Dispose() 194 { 195
196 } 197 } 198
199 }
ios實現代碼ios
1 using System; 2 using System.IO; 3 using Foundation; 4 using MobileOperation.iOS.WebCS; 5 using MobileOperation.Views; 6 using WebKit; 7 using Xamarin.Forms; 8 using Xamarin.Forms.Platform.iOS; 9
10 [assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))] 11 namespace MobileOperation.iOS.WebCS 12 { 13 public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler 14 { 15 const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}"; 16 WKUserContentController _userController; 17
18 protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e) 19 { 20 base.OnElementChanged(e); 21
22 if (Control == null) 23 { 24 _userController = new WKUserContentController(); 25 var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false); 26 _userController.AddUserScript(script); 27 _userController.AddScriptMessageHandler(this, "invokeAction"); 28
29 var config = new WKWebViewConfiguration { UserContentController = _userController }; 30 var webView = new WKWebView(Frame, config); 31 SetNativeControl(webView); 32 } 33 if (e.OldElement != null) 34 { 35 _userController.RemoveAllUserScripts(); 36 _userController.RemoveScriptMessageHandler("invokeAction"); 37 var hybridWebView = e.OldElement as HybridWebView; 38 } 39 if (e.NewElement != null) 40 { 41 string fileName = Path.Combine(NSBundle.MainBundle.BundlePath, string.Format("Web/{0}", Element.Uri)); 42 Control.LoadRequest(new NSUrlRequest(new NSUrl(fileName, false))); 43
44 Control.LoadRequest(new NSUrlRequest(new NSUrl(string.Format("http://192.168.50.148/baidu/index.html")))); 45 var hybirdWebView = e.NewElement; 46 //Control.UIDelegate = new MyWKUIDelegate();
47 hybirdWebView.RegisterInvokeJsFunctionAgent((s,action) =>
48 { 49 string jsInvokeStr = string.Format("javascript: {0}", s); 50 Control.EvaluateJavaScript(jsInvokeStr, (rs, error) =>
51 { 52 if (action!=null) 53 action(rs.ToString()); 54 }); 55 }); 56
57 } 58 } 59
60 public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message) 61 { 62 Element.InvokeAction(message.Body.ToString()); 63 } 64 } 65
66 public class MyWKUIDelegate : WKUIDelegate 67 { 68 public override void RunJavaScriptAlertPanel(WKWebView webView, string message, WKFrameInfo frame, Action completionHandler) 69 { 70 base.RunJavaScriptAlertPanel(webView, message, frame, completionHandler); 71 } 72
73 public override void RunJavaScriptTextInputPanel(WKWebView webView, string prompt, string defaultText, WKFrameInfo frame, 74 Action<string> completionHandler) 75 { 76 base.RunJavaScriptTextInputPanel(webView, prompt, defaultText, frame, completionHandler); 77 } 78
79
80 public override void RunJavaScriptConfirmPanel(WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler) 81 { 82 base.RunJavaScriptConfirmPanel(webView, message, frame, completionHandler); 83 } 84 } 85
86
87 }
c#調用js android實現:git
因爲android api問題在4.4如下只能傳參而沒有返回值,4.4以上使用相應方法(可是我試過了是沒有返回值的,緣由未知)github
1 hybirdWebView.RegisterInvokeJsFunctionAgent((s, action) =>
2 { 3 string jsInvokeStr = string.Format("javascript: {0}", s); 4
5 // 若是android運行版本高於4.4則調用該版本及其以上所支持的函數
6 if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat) 7 { 8 Control.EvaluateJavascript(jsInvokeStr, new ValueCallback(Control)); 9 } 10 else
11 { 12 // todo 此處調用自己並不支持有返回值
13 Control.LoadUrl(jsInvokeStr); 14 } 15
16 //res http://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/
17
18 // todo 目前在android還沒法實現有返回值
19 if (action != null) 20 { 21 action(string.Empty); 22 } 23 });
IOS實現:親測ios是有返回值web
hybirdWebView.RegisterInvokeJsFunctionAgent((s,action) => { string jsInvokeStr = string.Format("javascript: {0}", s); Control.EvaluateJavaScript(jsInvokeStr, (rs, error) => { if (action!=null) action(rs.ToString()); }); });
js調用c#在demo裏面已經實現了swift
在2.0版本的百度地圖因爲其js與移動端雙指縮放處理bug當地圖添加一些標註後縮放到必定時候地圖卡死,解決辦法將地圖版本下降到1.5版本,對於百度地圖嘛天然是無語的,下面請看
1 <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.5&ak=ak"></script>
連接:http://tieba.baidu.com/p/1724327638
在代碼裏面已經實現天然的須要添加權限,重寫webclient控件,因爲移動手機的瀏覽器內核通常都支持h5,因此只須要調用百度地圖的定位api便可經過本質上調用瀏覽器定位api輕鬆實現定位
連接:http://developer.baidu.com/map/jsdemo.htm#i8_1
android webview的性能不咋個好,可是組織好html的渲染過程仍是能夠接受的