Firemonkey扩展增强:Android 浏览器支持Input file标签上传功能

本文背景:Delphi XE10.2 Tokyo

Firemonkey自带的浏览器TWebbrower控件在Android平台上只是简单继承封装了Android系统本身的WebView组件。Android WebView 由于安全等原因本身并没有实现 <input type="file"/> 标签的选择文件功能,而是预留了一个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;

interface

uses 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<JFMXWebChromeClientClass,JFMXWebChromeClient>) 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;

implementation

uses 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设计一个简单的测试页面。

前端网页代码:

<html>
    <body>
        <form action="http://192.168.1.99/upload.php" method="post" enctype="multipart/form-data">
            <input οnchange="document.forms[0].submit();" type="file" name="file" />
        </form>
    </body>
</html>

upload.php代码:

echo '<pre>';
print_r($_FILES["file"]);
echo '</pre>';

在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”(麦克风)。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值