2013-06-04 47 views
2

我正在使用Xamarin框架构建HTML5应用程序原型。我正尝试将JavaScript连接到C#代码,反之亦然。Monotouch/Mono for Android Javascript to C#

这样做的最好方法是什么?到目前为止,我已经尝试创建Mono C#绑定到Cordova框架,这不是一个理想的解决方案,并且正在寻找更直接的东西,它利用了一种常见的.Net中心方法。所以我尝试设置一个HttpListener来处理来自javacript调用的应用http请求。这种方法与MonoTouch的效果很好,但与单不确实为Android

JavaScript调用:

<script type="text/javascript"> 
    function myFunction() 
    { 
     var request = new XMLHttpRequest(); 
     request.open('GET','http://127.0.0.1:8001/callnative', false); 
     request.send(); 

     if(request.status == 200){ 
      alert("Callback!"); 
     } 
     else{ 
      alert("Error"); 
     } 
    } 
</script> 

这里是Activity类的C#代码:

[Activity (Label = "AnroidHTML5Prototype", MainLauncher = true)] 
    public class Activity1 : Activity 
    { 
     int count = 1; 

     public HttpListener listener; 

     protected override void OnCreate (Bundle bundle) 
     { 
      base.OnCreate (bundle); 

      SetupListener(); 

      // Set our view from the "main" layout resource 
      SetContentView (Resource.Layout.Main); 

      // Get our button from the layout resource, 
      // and attach an event to it 
      Button button = FindViewById<Button> (Resource.Id.myButton); 

      button.Click += delegate { 
       button.Text = string.Format ("{0} clicks!", count++); 
      }; 

      LoadWebView(); 
     } 

     private void LoadWebView() 
     { 
      string lfn = "index.html"; 
      string html = string.Empty; 

      // context could be ApplicationContext, Activity or 
      // any other object of type Context 
      using (var input = this.ApplicationContext.Assets.Open(lfn)) 
       using (StreamReader sr = new System.IO.StreamReader(input)) 
      { 
       html = sr.ReadToEnd(); 
      } 

      WebView webView = FindViewById<WebView> (Resource.Id.webView1); 
      webView.SetWebChromeClient(new WebChromeClient()); 
      webView.Settings.JavaScriptEnabled = true; 
      webView.LoadData (html, "text/html", null); 
      webView.Settings.AllowFileAccess = true; 
      webView.Settings.BlockNetworkLoads = false; 
     } 

     private void SetupListener() { 
      listener = new HttpListener(); 
      listener.Prefixes.Add("http://*:8001/"); 
      listener.Start(); 

      listener.BeginGetContext(new AsyncCallback(HandleRequest), listener); 
     } 

     public void HandleRequest (IAsyncResult result) 
     { 
      RunOnUiThread(delegate{ 

       //Get the listener context 
       HttpListenerContext context = listener.EndGetContext(result); 

       //Start listening for the next request 
       listener.BeginGetContext(new AsyncCallback(HandleRequest), listener); 

       string response = String.Empty; 

       if (context.Request.Url.ToString().Contains ("callnative")) { 
        response = "native code reply"; 
       } 

       byte[] responseBytes = System.Text.Encoding.UTF8.GetBytes(response); 

       context.Response.ContentType = "text/json"; 
       context.Response.StatusCode = (int)HttpStatusCode.OK; 
       context.Response.ContentLength64 = responseBytes.Length; 
       context.Response.OutputStream.Write(responseBytes, 0, responseBytes.Length); 
       context.Response.OutputStream.Close(); 


//   WebView webView = FindViewById<WebView> (Resource.Id.webView1); 
//   webView.LoadUrl("javascript:(function() { " + 
//       "alert('Callback!'); " + 
//       "})()"); 

      }); 
     } 
    } 

类似的代码工作正常在Monotouch中,但在Android的Mono中,出现以下错误: [Web控制台] XMLHttpRequest无法加载http:// 127.0.0.1:8001/callnative。无法发出任何空请求:1 [Web控制台]未捕获错误:NETWORK_ERR:XMLHttpRequest异常101:1

我认为这与Chrome浏览器文件权限有关,因此我将WebView上的AllowFileAccess设置设置为是的,但仍然会出现同样的错误。

有没有更好的方法来实现在单声道JavaScript和C#之间的桥梁,或获得HTTPListener代码与Android的工作方式?

这篇文章出现在Xamarin文档的搜索,但它是一个404:

http://docs.xamarin.com/recipes/android/controls/webview/call_c#_from_javascript

感谢 德里克

+0

正确的URL该样本是这一个:http://docs.xamarin.com/recipes/android/controls/webview/call_c%23_from_javascript –

回答

1

我能够通过扩展连接JS和C#中单为Android WebViewClient并覆盖ShouldOverrideUrlLoading方法:

活动类别:

using Android.Runtime; 
using Android.Views; 
using Android.Widget; 
using Android.OS; 
using Android.Webkit; 
using System.IO; 
using System.Net; 
using System.Text; 

namespace AnroidHTML5Prototype 
{ 
    [Activity (Label = "AnroidHTML5Prototype", MainLauncher = true)] 
    public class Activity1 : Activity 
    { 
     protected override void OnCreate (Bundle bundle) 
     { 
      WebView webView = new WebView (this); 
      webView.Settings.JavaScriptEnabled = true; 
      webView.SetWebChromeClient(new WebChromeClient()); 
      string html = "<html><head><title></title></head><body><h1 id='button'>Hello Android</h1><h1 id='message' style='color:red'></h1><script>document.getElementById('button').onclick=function(){window.location='/callnative';}; function callback(msg){document.getElementById('message').innerHTML = msg;}</script></body></html>"; 
      webView.LoadData (html, "text/html", null); 
      webView.SetWebViewClient (new MyWebViewClient(webView)); 

      base.OnCreate (bundle); 
      SetContentView (webView); 
     } 
    } 
} 

扩展WebViewClient类:

using System; 
using Android.Webkit; 
using Java.IO; 
using Java.Net; 

namespace AnroidHTML5Prototype 
{ 
    public class MyWebViewClient : WebViewClient 
    { 
     WebView webView; 
     public MyWebViewClient (WebView webView) : base() 
     { 
      this.webView = webView; 
     } 

     public override bool ShouldOverrideUrlLoading (WebView view, string url) 
     { 
      if (url == "/callnative") 
      { 
       webView.LoadUrl ("javascript:callback('Hello from Android Native');"); 
       return true; 
      } 

      return base.ShouldOverrideUrlLoading(view, url); 
     } 
    } 
} 
0

在Android上的本地主机IP(仿真正在运行的计算机的IP)是不是127.0.0.1

这是10.0.2.2 ref 可能或者可能不是你的错误的来源。

0

感兴趣的人 - 我能不

RunOnUiThread(delegate{ 

而且在我的HTML文件中运行初始代码示例中,我使用jQuery的AJAX调用

<script type="text/javascript" src="../../js/jquery-1.9.1.js"></script> 
    ... 
<script type="text/javascript"> 
    $(document).ready(function() { 
     $('#example-1').click(function() { 
      $.ajax({ 
       async: true, 
       url: 'http://localhost:8801/test/url/test.htm' 
      }); 
      $(this).load('ProgressDialog.htm'); 
     }); 
    }); 
</script> 

您可能还注意到,本地主机是使用而不是127.0.0.1所以基本上相同的代码在Xamarin.iOS和Xamarin.Android上都适用。

我们这样做的的Mac的Windows使用共享同一个代码库与WebKit.NETMonobjcWebKit的网页流量控制跨平台的桌面应用程序的HTML。完全免费的工具集,顺便说一句,包括为Mac InApps(是米格尔,999 $每个平台的方式太多,大多数人,包括我自己;)从那个应用程序的工作,我知道只有这样的东西

.EvaluateJavaScript(..) 

需求被调用在main(aka UI)线程上(当然还有所有UI的东西),所以不知道为什么你在你的问题的代码示例中使用了RunOnUiThread

希望这将帮助别人:)