• Xamainr 地图之webview初探


    一 说几点

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

    二 xamarin地图实现及其问题

       gis作为软件领域基础性存在,比之传统表格列表等图形化展现数据优势。在app中由于国内国外墙原因一般都使用三方api,百度,高德,腾讯之类,其中高德自然是国内做得最专业的在线地图服务商,他们的api都很简单,所要注意一点就是坐标系,因为坐标系的原因常常标注一些地物要素对不上号。像传统老牌arcgis在移动领域其实也只是刷存在感。在xamarin中要开发地图应用自然的不得不使用三方,原因嘛android绑定了谷歌,ios嘛绑定了高德地图api功能又不够强大。怎么办的用高德,百度,腾讯,那么问题来了,xamarin使用三方库,这地方非常蛋疼,原因嘛xamarin其实将原生库元素据提取出来与c#语法映射,什么jar,.a ,.framework用很不成熟的sharpie工具反射,其实在这个过程中千丝万缕的牵涉到原生的oc姿势,不得不说非常蛋疼。即使你能够看懂官方英文,demo各种类型对应,问题还是会不少,不是缺个类就是函数签名对不上号,要么就是即使能is某个类型但as却编译不过。

    三 面对问题怎么办?

      问题自然是要解决的,随着h5的完善webview不失为更好一种办法,说白了就是把网页嵌入到页面中用c#与js交互,在这里以百度js api为例。

      在xamarin.android中由于4.4版本以下浏览器内核存在天生渲染慢加载慢等不足,在xamarin.ios自8.0后增强优化wkwebview控件。

    四 需求与实现

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

    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实现代码

     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实现:

    由于android api问题在4.4以下只能传参而没有返回值,4.4以上使用相应方法(但是我试过了是没有返回值的,原因未知)

     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是有返回值

    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里面已经实现了

    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截图

     

  • 相关阅读:
    马云演讲:给自己一个梦想,给自己一个承诺,给自己一个坚持!
    转:如何成为一个伟大的开发者
    数据挖掘之七种常用的方法
    windows命令行
    100万亿意味着什么?
    ubuntu环境配置
    Ubuntu runlevel修改
    Ubuntu 用户及组管理
    Git学习笔记
    Git详解之三 Git分支
  • 原文地址:https://www.cnblogs.com/rjjs/p/5303897.html
Copyright © 2020-2023  润新知