Firemonkey扩展增强:Android(安卓)浏览器支持Input file标签上传功能
本文背景:Delphi XE10.2 Tokyo
Firemonkey自带的浏览器TWebbrower控件在Android平台上只是简单继承封装了Android系统本身的WebView组件。Android WebView 由于安全等原因本身并没有实现 标签的选择文件功能,而是预留了一个setWebChromeClient方法来设置替换默认的Chrome处理。
关于WebChromeClient,它既不是接口也不是抽象类,但声明的方法很多方法体都是空的,通过这个WebChromeClient,我们可以自定义实现Webview对话框处理。这里为了实现input标签选文件功能,我们只需重写WebChromeClient中关于文件选择的方法onShowFileChooser和openFileChooser,前者是Android5.0公布的新接口,后者是Android4.1未公布(隐藏)的一个接口。
由于涉及Java类的继承,这里直接使用Java代码实现一个自定义的FMXWebChromeClient,并将其编译成Jar包,就可以在Delphi中使用。FMXWebChromeClient定义了一个选择监听器接口来自定义选择文件的逻辑处理,并且定义了doCallback回调函数来通知Webview并回传用户的选择结果。
unit tu2.fmxhelper.webchromeclient;interfaceuses Androidapi.JNIBridge, Androidapi.JNI.JavaTypes, Androidapi.JNI.Webkit, System.Messaging, System.Types;type [JavaSignature('tu2/fmx/webchromeclient/FMXWebChromeClient$OnChooserListener')] JOnChooserListener = interface(IJavaInstance) ['{0543AA53-85A1-48A1-A7B1-133C776850D3}'] procedure onExecute(acceptType: JString; capture: JString); cdecl; end; [JavaSignature('tu2/fmx/webchromeclient/FMXWebChromeClient')] JFMXWebChromeClient = interface(JWebChromeClient) ['{16615C3F-6ABC-4CA0-BA77-6B002F22F2DA}'] procedure setChooserListener(listener: JOnChooserListener); cdecl; procedure doCallback(filename: JString); cdecl; end; JFMXWebChromeClientClass = interface(JWebChromeClientClass) ['{DC8D9CA9-31AD-4BDD-9A81-030C2286B16B}'] function init: JFMXWebChromeClient; cdecl; end; TJFMXWebChromeClient = class(TJavaGenericImport) end; TImageChooserListener = class(TJavaLocal, JOnChooserListener) private FSize: TSize; [Weak]FChrome: JFMXWebChromeClient; procedure DidReceivedImagePath(const Sender: TObject; const M: TMessage); procedure DidCancelReceiveImage(const Sender: TObject; const M: TMessage); public procedure onExecute(acceptType: JString; capture: JString); cdecl; public constructor Create(const AChrome: JFMXWebChromeClient); destructor Destroy; override; end;implementationuses FMX.Platform.Android, FMX.Platform, FMX.Graphics, AndroidApi.Helpers;{ TImageChooserListener }constructor TImageChooserListener.Create;begin inherited Create; if AChrome<>nil then begin FChrome := AChrome; FChrome.setChooserListener(Self); end; FSize.cx := TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize); FSize.cy := TCanvasManager.DefaultCanvas.GetAttribute(TCanvasAttribute.MaxBitmapSize); TMessageManager.DefaultManager.SubscribeToMessage(TMessageCancelReceivingImage, DidCancelReceiveImage); TMessageManager.DefaultManager.SubscribeToMessage(TMessageReceivedImagePath, DidReceivedImagePath);end;destructor TImageChooserListener.Destroy;begin TMessageManager.DefaultManager.Unsubscribe(TMessageReceivedImagePath, DidReceivedImagePath); TMessageManager.DefaultManager.Unsubscribe(TMessageCancelReceivingImage, DidCancelReceiveImage); inherited;end;procedure TImageChooserListener.DidCancelReceiveImage(const Sender: TObject; const M: TMessage);begin if FChrome<>nil then FChrome.doCallback(StringToJString(''));end;procedure TImageChooserListener.DidReceivedImagePath(const Sender: TObject; const M: TMessage);var ImagePath: string;begin if (FChrome<>nil) and (M is TMessageReceivedImagePath) then begin ImagePath := 'file://' + (M as TMessageReceivedImagePath).Value; FChrome.doCallback(StringToJString(ImagePath)); end;end;procedure TImageChooserListener.onExecute(acceptType, capture: JString);begin MainActivity.getFMXMediaLibrary.takeImageFromLibrary(FSize.Width, FSize.Height, False);end;end.
TImageChooserListener是用Delphi实现的图片选择器实现类,使用上我们只需在FMX.WebBrowser.Android单元的TAndroidWebBrowserService.InitUIThread方法中创建一个FMXWebChromeClient对象和相应的TImageChooserListener对象实例,并通过setWebChromeClient方法与Webview绑定,就可以使webview支持文件的上传功能。这里不再赘述,具体参考Demo。
完整Demo:下载。为了测试,我们用PHP设计一个简单的测试页面。
前端网页代码:
upload.php代码:
echo '';print_r($_FILES["file"]);echo '
';
在Windows平台下浏览器测试返回如下结果:
在Android平台下测试我们的Demo界面结果截图。
关于acceptType, capture参数的补充:
TImageChooserListener在onExecute中只是简单的调用了Firemonkey的标准Action从相册选图片,并没有判断acceptType, capture参数。acceptType参数对应input标签的Accept属性,通过acceptType可以判断要选择的是图片,视频,音频等;capture代表需要开启的Capturing功能。
在android5.0及更高版本中,capture=“capture”代表支持Capturing功能,通过acceptType来判断要开启capture的设备是camera/camcorder/microphone。在android4.4及之前版本中capture的可能取值有:“”,“filesystem”,“camera”(相机),“camcorder”(摄像机),“microphone”(麦克风)。
更多相关文章
- 给android系统添加自己想要的属性
- Android(安卓)网络编程 API笔记 - java.net 包 权限 地址 套接字
- Android以太网框架情景分析之NetworkFactory与NetworkAgent深入
- 神奇的 Magisk
- 【较详细】Andriod 从源码的角度详解View,ViewGroup的Touch事件
- 关于Android(安卓)Service真正的完全详解,你需要知道的一切
- Android(安卓)Lifecycle的一些感悟
- Android进阶笔记10:Android(安卓)万能适配器
- Android(安卓)退出Activity