나는 어떻게 작동시키는 지 알고 있습니다. 그 중 일부는 늪지대의 표준 인 "가상의 방법을 묶는 법"이며, 그 일부는 순수한 사악한 악이다.
첫째, 우리는 "중개자"가 필요합니다. WebChromeClient
은 openFileChooser()
메서드를 선언하지 않으므로 OpenFileWebChromeClient
이라는 버전을 선언해야합니다. 그것은 virtual
OpenFileChooser
방법을 선언하고, 오버라이드 (override) 할 수 있도록 그것에 대한 바인딩을 제공합니다
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
을 사용한다는 점을 제외하고는 귀하가 언급 한 블로그 게시물과 동일합니다.
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;
}
}
}
}
슬프게도, 지금 순수 완화되지 않은 악한 행위를위한 시간이다 : 나는 또한 OnActivityResult()
수신하는 URI를 표시하는 몇 가지 논리를 업데이트했습니다. 위의 MyOpenFileWebChromeClient
선언의 문제는 M0S의 블로그가 익명의 내부 클래스 선언에 @Override
을 사용할 수없는 것과 동일한 이유 때문에 작동하지 않는다는 것입니다. 앱을 빌드하는 android.jar
은 openFileChooser()
을 선언하지 않습니다. 방법.
빌드 프로세스는 유효한 Java 코드를 포함해야하는 Android Callable Wrappers을 생성합니다. 문제는 생성 된 코드는 MyOpenFileWebChromeClient
의 안드로이드 호출 가능 래퍼의 결과로 재정의 방법 및 인터페이스 방법에 대한 @Override
을 사용한다는 것입니다 : 컴파일러 오류가 발생합니다 분명히
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();
}
}
MyOpenFileWebChromeClient.openFileChooser()
에 @Override
을, 어떻게 우리가이 일을해야합니까 ? @Override
주석을 제공함으로써!
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 {
}
장소 위의 Override.java
라는 이름의 파일이 프로젝트에 추가 한 AndroidJavaSource
에 자사의 빌드 작업을 설정으로.
우리는 MyOpenFileWebChromeClient
유형과 동일한 패키지에 사용자 정의 @Override
주석을 제공하기 때문에 결과 프로젝트가 작동합니다. (결과적으로 생성 된 패키지 이름이 무엇인지 알기 때문에이 작업을 수행하는 모든 패키지에 대해 별도의 @Override
주석을 제공해야합니다.) 동일한 패키지의 형식이 가져온 이름보다 우선합니다. 심지어 이름이 java.lang
에서 오는 경우도 있으므로 사용자 정의 @Override
주석이 컴파일 될뿐만 아니라 java.lang.Override
주석보다 우선하여 MyOpenFileWebChromeClient
android callable wrapper에서 사용됩니다.
나는 그것이 순수한 악몽이라고 말 했나요?
신의 어머니! 이것이 작동하도록하는 몇 가지 해결 방법입니다. 다행히 Android 4.2 용 Mono에서 수정되었습니다! http://docs.xamarin.com/android/Releases/Mono_For_Android_4/Mono_For_Android_4.2#Bug_Fixes – Cheesebaron
수정되었습니다. 파일 업로드 팝업이 내 측면의 webview에서 작동하지 않습니다. –