我有一個想法如何使它工作。其中一部分是沼澤標準的「如何綁定一種虛擬方法」,其中的一部分是純粹的邪惡。
首先,我們需要一個「中介」。由於WebChromeClient
未聲明openFileChooser()
方法,因此我們需要聲明一個名爲OpenFileWebChromeClient
的版本。它聲明virtual
OpenFileChooser
方法,併爲它的綁定,以便它可以被覆蓋:
using System;
using Android.App;
using Android.Content;
using Android.Runtime;
using Android.OS;
using Android.Webkit;
namespace Scratch.FileUpload
{
[Register ("android/webkit/WebChromeClient", DoNotGenerateAcw=true)]
class OpenFileWebChromeClient : WebChromeClient {
static IntPtr id_openFileChooser;
[Register ("openFileChooser", "(Landroid/webkit/ValueCallback;)V", "GetOpenFileChooserHandler")]
public virtual void OpenFileChooser (IValueCallback uploadMsg)
{
if (id_openFileChooser == IntPtr.Zero)
id_openFileChooser = JNIEnv.GetMethodID (ThresholdClass, "openFileChooser", "(Landroid/webkit/ValueCallback;)V");
if (GetType() == ThresholdType)
JNIEnv.CallVoidMethod (Handle, id_openFileChooser, new JValue (JNIEnv.ToJniHandle (uploadMsg)));
else
JNIEnv.CallNonvirtualVoidMethod (Handle, ThresholdClass, id_openFileChooser, new JValue (JNIEnv.ToJniHandle (uploadMsg)));
}
#pragma warning disable 0169
static Delegate cb_openFileChooser;
static Delegate GetOpenFileChooserHandler()
{
if (cb_openFileChooser == null)
cb_openFileChooser = JNINativeWrapper.CreateDelegate ((Action<IntPtr, IntPtr, IntPtr>) n_OpenFileChooser);
return cb_openFileChooser;
}
static void n_OpenFileChooser (IntPtr jnienv, IntPtr native__this, IntPtr native_uploadMsg)
{
OpenFileWebChromeClient __this = Java.Lang.Object.GetObject<OpenFileWebChromeClient> (native__this, JniHandleOwnership.DoNotTransfer);
var uploadMsg = Java.Lang.Object.GetObject<IValueCallback> (native_uploadMsg, JniHandleOwnership.DoNotTransfer);
__this.OpenFileChooser (uploadMsg);
}
#pragma warning restore 0169
}
}
接下來,因爲C#缺少的匿名內部類,我們需要一個明確的類,命名爲MyOpenFileWebChromeClient
這裏:
namespace Scratch.FileUpload {
class MyOpenFileWebChromeClient : OpenFileWebChromeClient {
Action<IValueCallback> cb;
public MyOpenFileWebChromeClient(Action<IValueCallback> cb)
{
this.cb = cb;
}
public override void OpenFileChooser (IValueCallback uploadMsg)
{
cb (uploadMsg);
}
}
活動端口與您提到的博客文章完全相同,只是它使用MyOpenFileWebChromeClient
而不是匿名內部類。我也更新了一些邏輯來顯示的URI OnActivityResult()
接收:
namespace Scratch.FileUpload {
[Activity (Label = "Scratch.FileUpload", MainLauncher = true)]
public class Activity1 : Activity
{
private WebView wv;
private IValueCallback mUploadMessage;
const int FilechooserResultcode = 1;
protected override void OnCreate (Bundle bundle)
{
base.OnCreate (bundle);
wv = new WebView (this);
wv.SetWebViewClient(new WebViewClient());
wv.SetWebChromeClient(new MyOpenFileWebChromeClient(uploadMsg => {
mUploadMessage = uploadMsg;
var intent = new Intent (Intent.ActionGetContent);
intent.AddCategory(Intent.CategoryOpenable);
intent.SetType("image/*");
StartActivityForResult(Intent.CreateChooser(intent, "File Chooser"),
FilechooserResultcode);
}));
SetHtml(null);
SetContentView(wv);
}
void SetHtml(string filename)
{
string html = @"<html>
<body>
<h1>Hello, world!</h1>
<p>Input Box:</p>
<input type=""file"" />
<p>URI: " + filename + @"
</body>
</html>";
wv.LoadData(html, "text/html", "utf-8");
}
protected override void OnActivityResult (int requestCode, Result resultCode, Intent data)
{
base.OnActivityResult (requestCode, resultCode, data);
if (requestCode == FilechooserResultcode) {
if (mUploadMessage == null)
return;
var result = data == null || resultCode != Result.Ok
? null
: data.Data;
SetHtml(result.ToString());
mUploadMessage.OnReceiveValue(result);
mUploadMessage = null;
}
}
}
}
可悲的是,現在是時候爲純十惡不赦的行爲。 MyOpenFileWebChromeClient
的上述聲明的問題在於它不起作用,因爲M0S的博客在匿名內部類聲明中不能使用@Override
:您構建應用程序的android.jar
未聲明openFileChooser()
方法。
構建過程將生成Android Callable Wrappers,其中必須包含有效的Java代碼。問題是,生成的代碼使用@Override
替代的方法和接口的方法,導致Android的可調用包裝爲MyOpenFileWebChromeClient
:
package scratch.fileupload;
public class MyOpenFileWebChromeClient
extends android.webkit.WebChromeClient
{
static final String __md_methods;
static {
__md_methods =
"n_openFileChooser:(Landroid/webkit/ValueCallback;)V:GetOpenFileChooserHandler\n" +
"";
mono.android.Runtime.register ("Scratch.FileUpload.MyOpenFileWebChromeClient, Scratch.FileUpload, Version=1.0.0.0, Culture=neutral, PublicKeyToken=null", MyOpenFileWebChromeClient.class, __md_methods);
}
@Override
public void openFileChooser (android.webkit.ValueCallback p0)
{
n_openFileChooser (p0);
}
private native void n_openFileChooser (android.webkit.ValueCallback p0);
java.util.ArrayList refList;
public void monodroidAddReference (java.lang.Object obj)
{
if (refList == null)
refList = new java.util.ArrayList();
refList.add (obj);
}
public void monodroidClearReferences()
{
if (refList != null)
refList.clear();
}
}
顯然@Override
上MyOpenFileWebChromeClient.openFileChooser()
將產生一個編譯器錯誤,那麼,我們如何使這項工作? 通過提供我們自己的@Override
註釋!上述到一個名爲Override.java
文件,將其添加到項目中,其生成操作設置爲AndroidJavaSource
package scratch.fileupload;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
廣場。
生成的項目的工作原理是因爲我們在與MyOpenFileWebChromeClient
類型相同的包中提供了自定義的@Override
註釋。 (因此,這要求您知道生成的包名稱是什麼,並且您爲每個包提供單獨的@Override
註釋。)同一包中的類型優先於導入的名稱,甚至來自java.lang
的名稱,因此我們的自定義@Override
註釋不僅可以編譯,而且還可以被MyOpenFileWebChromeClient
機器人可調用包裝器使用,優先於java.lang.Override
註解。
我確實說過這是純粹的邪惡,不是嗎?
上帝之母!這是一個解決方法,讓這個工作。幸運的是它已經在Mono for Android 4.2中得到修復! http://docs.xamarin.com/android/Releases/Mono_For_Android_4/Mono_For_Android_4.2#Bug_Fixes – Cheesebaron 2012-05-16 14:15:13
這是固定的。文件上傳彈出不在我身邊的webview工作 – 2018-02-02 16:45:58