Xamainr 地图之webview初探

一 说几点

   当下移动开发主要实现方式有传统的Native以及新的混合开发想Rect.js,nodejs这些前段框架,其本质要么是原生控件来实现UI,要么html来实现UI。Xamarin其实也只是取巧而已,目的在于方便net开发者再学习java以及蛋疼的oc和不成熟的swift,好了废话很少说了。javascript

 

二 xamarin地图实现及其问题

   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

四 需求与实现

1 怎样把地图html页面嵌入到app页面,在这里xamarin为咱们提供了很好的demo

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&center_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 }
View Code

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 }
View Code

 

 

2 c#与js如何交互:

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                 });
View Code

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()); }); });
View Code

js调用c#在demo里面已经实现了swift

3 粗线的问题

在2.0版本的百度地图因为其js与移动端双指缩放处理bug当地图添加一些标注后缩放到必定时候地图卡死,解决办法将地图版本下降到1.5版本,对于百度地图嘛天然是无语的,下面请看

1 <script type="text/javascript" src="http://api.map.baidu.com/api?v=1.5&ak=ak"></script>
View Code

连接:http://tieba.baidu.com/p/1724327638

 4 定位

在代码里面已经实现天然的须要添加权限,重写webclient控件,因为移动手机的浏览器内核通常都支持h5,因此只须要调用百度地图的定位api便可经过本质上调用浏览器定位api轻松实现定位

连接:http://developer.baidu.com/map/jsdemo.htm#i8_1

5 性能

 android webview的性能不咋个好,可是组织好html的渲染过程仍是能够接受的

6截图

 

 

相关文章
相关标签/搜索