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实现代码
using System;
using Android.Net.Http;
using Android.OS;
using Android.Webkit;
using MobileOperation.Droid.Web;
using MobileOperation.Views;
using Xamarin.Forms;
using Xamarin.Forms.Platform.Android;
using View = Android.Views.View;
using WebView = Android.Webkit.WebView; [assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace MobileOperation.Droid.Web
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, Android.Webkit.WebView>, IDownloadListener, View.IOnLongClickListener
{
const string JavaScriptFunction = "function invokeCSharpAction(data){jsBridge.invokeAction(data);}"; protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e); if (Control == null)
{
var webView = new Android.Webkit.WebView(Forms.Context);
webView.Settings.JavaScriptEnabled = true;
webView.SetDownloadListener(this);
SetNativeControl(webView);
}
if (e.OldElement != null)
{
Control.RemoveJavascriptInterface("jsBridge");
var hybridWebView = e.OldElement as HybridWebView; }
if (e.NewElement != null)
{ Control.AddJavascriptInterface(new JSBridge(this), "jsBridge");
//Control.LoadUrl(string.Format("file:///android_asset/Web/{0}", Element.Uri));
InjectJS(JavaScriptFunction); Control.Settings.JavaScriptEnabled = true;
Control.SetWebChromeClient(new GeoWebChromeClient());
Control.SetWebViewClient(new MyWebViewClient());
Control.SetNetworkAvailable(true);
Control.Settings.SetGeolocationEnabled(true);
Control.Settings.JavaScriptCanOpenWindowsAutomatically = (true); Control.Settings.SetAppCacheEnabled(true);
Control.Settings.AllowFileAccess=(true);
Control.Settings.DomStorageEnabled=(true);
Control.Settings.SetSupportZoom(false);
Control.Settings.SetSupportMultipleWindows(false);
Control.Settings.BuiltInZoomControls=(false);
Control.Settings.SetRenderPriority(WebSettings.RenderPriority.High); Control.SetOnLongClickListener(this);
Control.ClearCache(true);
if ((int)Build.VERSION.SdkInt >= )
{
Control.Settings.LoadsImagesAutomatically=(true);
}
else
{
Control.Settings.LoadsImagesAutomatically=(false);
} var hybirdWebView = e.NewElement;
hybirdWebView.RegisterInvokeJsFunctionAgent((s, action) =>
{
string jsInvokeStr = string.Format("javascript: {0}", s); // 如果android运行版本高于4.4则调用该版本及其以上所支持的函数
if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
Control.EvaluateJavascript(jsInvokeStr, new ValueCallback(Control));
}
else
{
// todo 此处调用本身并不支持有返回值
Control.LoadUrl(jsInvokeStr);
} //res http://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/ // todo 目前在android还无法实现有返回值
if (action != null)
{
action(string.Empty);
}
});
//Control.LoadUrl(string.Format("http://map.baidu.com/mobile/webapp/index.html"));
Control.LoadUrl(string.Format("http://192.168.50.148/baidu/index.html"));
//Control.LoadUrl(string.Format("http://192.168.50.254"));
//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")); }
} void InjectJS(string script)
{
if (Control != null)
{
Control.LoadUrl(string.Format("javascript: {0}", script));
}
} public void OnDownloadStart(string url, string userAgent, string contentDisposition, string mimetype, long contentLength)
{ } public bool OnLongClick(View v)
{
return true; }
} public class GeoWebChromeClient : WebChromeClient
{
public override void OnGeolocationPermissionsShowPrompt(string origin, GeolocationPermissions.ICallback callback)
{
//允许通过权限询问访问
callback.Invoke(origin, true, false);
} } public class MyWebViewClient : WebViewClient
{
public override bool ShouldOverrideUrlLoading(WebView view, string url)
{
view.LoadUrl(url);
return true;
}
public override void OnPageFinished(WebView view, String url)
{
if (!view.Settings.LoadsImagesAutomatically)
{
view.Settings.LoadsImagesAutomatically=(true);
}
} public override void OnReceivedSslError(WebView view, SslErrorHandler handler, SslError error)
{
handler.Proceed();
} public override void OnReceivedError(WebView view, ClientError errorCode, string description, string failingUrl)
{
base.OnReceivedError(view, errorCode, description, failingUrl); } } public class ValueCallback : IValueCallback
{ private Android.Webkit.WebView webView; public ValueCallback(Android.Webkit.WebView wbView)
{
webView = wbView;
} public void OnReceiveValue(Java.Lang.Object value)
{ } public System.IntPtr Handle
{
get { return new IntPtr(); }
} public void Dispose()
{ }
} }
ios实现代码
using System;
using System.IO;
using Foundation;
using MobileOperation.iOS.WebCS;
using MobileOperation.Views;
using WebKit;
using Xamarin.Forms;
using Xamarin.Forms.Platform.iOS; [assembly: ExportRenderer(typeof(HybridWebView), typeof(HybridWebViewRenderer))]
namespace MobileOperation.iOS.WebCS
{
public class HybridWebViewRenderer : ViewRenderer<HybridWebView, WKWebView>, IWKScriptMessageHandler
{
const string JavaScriptFunction = "function invokeCSharpAction(data){window.webkit.messageHandlers.invokeAction.postMessage(data);}";
WKUserContentController _userController; protected override void OnElementChanged(ElementChangedEventArgs<HybridWebView> e)
{
base.OnElementChanged(e); if (Control == null)
{
_userController = new WKUserContentController();
var script = new WKUserScript(new NSString(JavaScriptFunction), WKUserScriptInjectionTime.AtDocumentEnd, false);
_userController.AddUserScript(script);
_userController.AddScriptMessageHandler(this, "invokeAction"); var config = new WKWebViewConfiguration { UserContentController = _userController };
var webView = new WKWebView(Frame, config);
SetNativeControl(webView);
}
if (e.OldElement != null)
{
_userController.RemoveAllUserScripts();
_userController.RemoveScriptMessageHandler("invokeAction");
var hybridWebView = e.OldElement as HybridWebView;
}
if (e.NewElement != null)
{
string fileName = Path.Combine(NSBundle.MainBundle.BundlePath, string.Format("Web/{0}", Element.Uri));
Control.LoadRequest(new NSUrlRequest(new NSUrl(fileName, false))); Control.LoadRequest(new NSUrlRequest(new NSUrl(string.Format("http://192.168.50.148/baidu/index.html"))));
var hybirdWebView = e.NewElement;
//Control.UIDelegate = new MyWKUIDelegate();
hybirdWebView.RegisterInvokeJsFunctionAgent((s,action) =>
{
string jsInvokeStr = string.Format("javascript: {0}", s);
Control.EvaluateJavaScript(jsInvokeStr, (rs, error) =>
{
if (action!=null)
action(rs.ToString());
});
}); }
} public void DidReceiveScriptMessage(WKUserContentController userContentController, WKScriptMessage message)
{
Element.InvokeAction(message.Body.ToString());
}
} public class MyWKUIDelegate : WKUIDelegate
{
public override void RunJavaScriptAlertPanel(WKWebView webView, string message, WKFrameInfo frame, Action completionHandler)
{
base.RunJavaScriptAlertPanel(webView, message, frame, completionHandler);
} public override void RunJavaScriptTextInputPanel(WKWebView webView, string prompt, string defaultText, WKFrameInfo frame,
Action<string> completionHandler)
{
base.RunJavaScriptTextInputPanel(webView, prompt, defaultText, frame, completionHandler);
} public override void RunJavaScriptConfirmPanel(WKWebView webView, string message, WKFrameInfo frame, Action<bool> completionHandler)
{
base.RunJavaScriptConfirmPanel(webView, message, frame, completionHandler);
}
} }
2 c#与js如何交互:
c#调用js android实现:
由于android api问题在4.4以下只能传参而没有返回值,4.4以上使用相应方法(但是我试过了是没有返回值的,原因未知)
hybirdWebView.RegisterInvokeJsFunctionAgent((s, action) =>
{
string jsInvokeStr = string.Format("javascript: {0}", s); // 如果android运行版本高于4.4则调用该版本及其以上所支持的函数
if (Build.VERSION.SdkInt >= BuildVersionCodes.Kitkat)
{
Control.EvaluateJavascript(jsInvokeStr, new ValueCallback(Control));
}
else
{
// todo 此处调用本身并不支持有返回值
Control.LoadUrl(jsInvokeStr);
} //res http://droidyue.com/blog/2014/09/20/interaction-between-java-and-javascript-in-android/ // todo 目前在android还无法实现有返回值
if (action != null)
{
action(string.Empty);
}
});
IOS实现:亲测ios是有返回值
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里面已经实现了
3 粗线的问题
在2.0版本的百度地图由于其js与移动端双指缩放处理bug当地图添加一些标注后缩放到一定时候地图卡死,解决办法将地图版本降低到1.5版本,对于百度地图嘛自然是无语的,下面请看
<script type="text/javascript" src="http://api.map.baidu.com/api?v=1.5&ak=ak"></script>
链接: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截图
Xamainr 地图之webview初探的更多相关文章
- [OC][地图] 高德地图之定位初探(一)
使用前的说明 高德地图开放平台的iOS定位模块网址-->http://lbs.amap.com/api/ios-location-sdk/summary/ 高德地图有Web端.android平台 ...
- 微信小程序室内地图导航开发-微信小程序JS加载esmap地图
一.在微信小程序里显示室内三维地图 需要满足的两个条件 调用ESMap室内地图需要用到小程序web-view组件,想要通过 web-view 调用ESMap室内地图需要满足以下 2 个条件: 1. 小 ...
- 支付宝小程序室内地图导航开发-支付宝小程序JS加载esmap地图
如果是微信小程序开发,请参考微信小程序室内地图导航开发-微信小程序JS加载esmap地图文章 一.在支付宝小程序里显示室内三维地图 需要满足的两个条件 调用ESMap室内地图需要用到小程序web-vi ...
- Android网络:开发浏览器(二)——功能完善之长按网页图片菜单
上述的历史和书签的功能已经实现.不过如果我们长时间按住图片,并不会出现如同UC中的一系列选项,我们可以来看看UC中的长按图片出现的菜单. 图10.2.9 UC中的长按图片菜单 我们可以看到UC中 ...
- Google Earth数据存储、管理、表现及开发机制
Google Earth数据存储.管理.表现及开发机制 一. Google Earth(Map)介绍 1.1 Google Earth介绍 在众多的地理信息服务提供商中,Google是较早 ...
- 前端笔记之微信小程序(一)初识微信小程序&WXSS与CSS|WXML与HTML的差异&像素和DPR
一.小程序概述 2017 年 1 月 9 日小程序正式上线,腾讯开放了个人开发者开发小程序,小程序从此就开始火爆,这一年,小程序狂揽 4 亿用户.1.7 亿的日常活跃,上线 58 万个.这是一个巨大的 ...
- Android中通过WebView控件实现与JavaScript方法相互调用的地图应用
在Android中通过WebView控件,可以实现要加载的页面与Android方法相互调用,我们要实现WebView中的addJavascriptInterface方法,这样html才能调用andro ...
- UE4高级功能--初探超大无缝地图的实现LevelStream
转自:http://blog.csdn.net/u011707076/article/details/44903223 LevelStream 实现超大无缝地图--官方文档学习 The Level S ...
- Baidu与Google地图API初探
前天周六,有个好友过来玩,他说想在他的站点中加入地图导航模块,但不知道选择哪个第三方Map API 在网上查了下Baidu.Google.QQ和MapBar等4种Map API(都是採用JS开放API ...
随机推荐
- kingso_module - Taocode
kingso_module - Taocode 模块介绍 Merger 功能介绍 Merger的功能: 合并多台Searcher机器的部分查询结果,得到最终的完整查询结果 向Detail集群请求最终展 ...
- LTP介绍
1.LTP介绍 LTP--linut test project ,ltp套件是由Linux Test Project所开发的一套系统測试套件.它基于系统资源的利用率统计开发了一个測试的组合,为系 ...
- 基于SOAP的xml网络交互心得
感谢小二同学将遇到的问题分享给我们,再此给以掌声.如果看不懂下面文章的建议查找一下HTTP协议的文艺,对HTTP协议要有个概念. XML网络交互心得 目录 一. xml解析 1.根路径下 2. ...
- 解决打包时IsCmdBld.exe出错的问题
1.查看环境变量是否配置了 2.查看是否是使用administrator登陆的,要求使用administrator登陆否则可能会出现权限不足的现象
- Python 第三篇(下):collections系列、集合(set)、单双队列、深浅copy、内置函数
一.collections系列: collections其实是python的标准库,也就是python的一个内置模块,因此使用之前导入一下collections模块即可,collections在py ...
- Intent数据传递
(1)首先是Activity的简单跳转: 1).Activity的切换一般是通过Intent来实现的,Intent是一个Activity到达另一个Activity的引路者,它描述了起点(当前Activ ...
- Gradle的简介与安装
Gradle介绍 Gradle是一个基于JVM的构建工具,它提供了: 像Ant一样,通用灵活的构建工具 可以切换的,基于约定的构建框架 强大的多工程构建支持 基于Apache Ivy的强大的依赖管理 ...
- 在程序中,你敢怎样使用“goto”语句!
用goto是一个个人爱好的问题.“我”的意见是,十个goto中有九个可以用相应的结构化结构来替换.在那些简单情形下,你可以完全替换掉goto,在复杂的情况下,十个中也有九个可以不用:你可以把部分代码写 ...
- PHP - 图像处理
第14章 处理图像 学习要点: 1.创建图像 2.简单小案例 在PHP5中,动态图象的处理要比以前容易得多.PHP5在php.ini文件中包含了GD扩展包,只需去掉GD扩展包的相应注释就可以正常使用了 ...
- 使用css3写一朵云