本文背景: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”(麦克风)。

更多相关文章

  1. 给android系统添加自己想要的属性
  2. Android(安卓)网络编程 API笔记 - java.net 包 权限 地址 套接字
  3. Android以太网框架情景分析之NetworkFactory与NetworkAgent深入
  4. 神奇的 Magisk
  5. 【较详细】Andriod 从源码的角度详解View,ViewGroup的Touch事件
  6. 关于Android(安卓)Service真正的完全详解,你需要知道的一切
  7. Android(安卓)Lifecycle的一些感悟
  8. Android进阶笔记10:Android(安卓)万能适配器
  9. Android(安卓)退出Activity

随机推荐

  1. IOS录制的视频在Android播放异常的问题
  2. 源码角度分析Android的事件输入系统(input
  3. android bitmap 缓存实现(OOM)
  4. Android中的服务有几种,具体实现步骤,这几
  5. 傻瓜式建立数据库,高效数据库操作代码的编
  6. 深入探索 Android 内存优化(炼狱级别)
  7. android音频系统音量控制探讨
  8. 在android状态栏上添加多个图标
  9. Android网络收音机项目(源码实例分享)
  10. android 标题栏下拉选择控件(下拉菜单宽度