zoukankan      html  css  js  c++  java
  • 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截图

     

  • 相关阅读:
    笨方法学python中执行argv提示ValueError: not enough values to unpack (expected 4, got 1)
    VMware workstation安装
    Redis bigkey分析
    MySQL drop table 影响及过程
    MySQL 大表硬连接删除
    ES elasticsearch 各种查询
    ES elasticsearch 各种聚合
    ES elasticsearch 聚合统计
    ES elasticsearch 实现 count单字段,分组取前多少位,以地理位置中心进行统计
    MySQL行溢出、varchar最多能存多少字符
  • 原文地址:https://www.cnblogs.com/rjjs/p/5303897.html
Copyright © 2011-2022 走看看