当下移动开发主要实现方式有传统的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的渲染过程仍是能够接受的