- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
用例(先是一些信息):
我制作了一些 HTML/CSS3/Javascript 游戏,它们可以在特定于平台的可执行文件中的 WebView/嵌入式浏览器中的不同平台上运行。我自己设计了它,因为我厌倦了周围的所有“框架”,它们告诉我使用他们的框架是多么简单。我不需要这些框架及其令人印象深刻的类和东西的所有膨胀,它必须像 ABC 一样简单,对吧?此外,由于 webview 比 native 代码慢,因此它必须简单直接才能获得最佳性能。
所以我设计了一个在 javascript 中作为变量可用的接口(interface),无需加载额外的 javascript 类(如 cordova 或 phonegap 或其他)。因为我也使用 Windows(Windows 无法将对象变量的名称更改为“publish”),所以它可以通过 javascript 通过 window.external 访问。当 html 加载到 webview/browser 中时,此变量将是一个对象。
问题
这一切都工作得很好(在不同的平台上)但是 window.external
变量在 Windows 上似乎是一个空对象,但是当你尝试调用像 window.external 这样的函数时.vibrate(500)
它将被无误地执行(该函数存在于该对象的所有平台版本中)。
但是,typeof window.external.vibrate
之类的结果会导致 'undefined'
。遍历对象什么都不做,例如:
for( var p in window.external ) {
alert( p );
}
因此,要测试外部对象是否是“真正的”外部对象并不容易,也无法查看支持哪些功能(如有必要)。
我该怎么办?我是否遗漏了什么?
为了给你一些信息,我遵循了这个“指南”: http://www.delphidabbler.com/articles?article=22 .
我的代码(简化版):
类型库:
unit WebBrowserBridge_TLB;
// ************************************************************************ //
// WARNING
// -------
// The types declared in this file were generated from data read from a
// Type Library. If this type library is explicitly or indirectly (via
// another type library referring to this type library) re-imported, or the
// 'Refresh' command of the Type Library Editor activated while editing the
// Type Library, the contents of this file will be regenerated and all
// manual modifications will be lost.
// ************************************************************************ //
// PASTLWTR : $Revision: 1.88.1.0.1.0 $
// File generated on 4-3-2014 6:50:23 from Type Library described below.
// ************************************************************************ //
// Type Lib: ExternalInterface\WebBrowserBridge.tlb (1)
// IID\LCID: {517F7078-5E73-4E5A-A8A2-8F0FF14EF21B}\0
// Helpfile:
// DepndLst:
// (1) v2.0 stdole, (C:\Windows\SysWOW64\stdole2.tlb)
// ************************************************************************ //
{$TYPEDADDRESS OFF} // Unit must be compiled without type-checked pointers.
interface
uses Windows, ActiveX, Classes, Graphics, OleServer, OleCtrls, StdVCL;
// *********************************************************************//
// GUIDS declared in the TypeLibrary. Following prefixes are used:
// Type Libraries : LIBID_xxxx
// CoClasses : CLASS_xxxx
// DISPInterfaces : DIID_xxxx
// Non-DISP interfaces: IID_xxxx
// *********************************************************************//
const
// TypeLibrary Major and minor versions
WebBrowserBridgeMajorVersion = 1;
WebBrowserBridgeMinorVersion = 0;
LIBID_WebBrowserBridge: TGUID = '{517F7078-5E73-XXXX-B8A2-8F0FF14EF21B}';
IID_IWebBrowserBridge: TGUID = '{4F995D09-XXXX-4042-993E-C71A8AED661E}';
type
// *********************************************************************//
// Forward declaration of types defined in TypeLibrary
// *********************************************************************//
IWebBrowserBridge = interface;
IWebBrowserBridgeDisp = dispinterface;
// *********************************************************************//
// Interface: IWebBrowserBridge
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {4F995D09-CF9E-XXX-993E-C71A8AED661E}
// *********************************************************************//
IWebBrowserBridge = interface(IDispatch)
['{4F995D09-CF9E-4042XXXX-C71A8AED661E}']
procedure isAvailable; safecall;
procedure vibrate(ms: Integer); safecall;
end;
// *********************************************************************//
// DispIntf: IWebBrowserBridgeDisp
// Flags: (4416) Dual OleAutomation Dispatchable
// GUID: {4F995D09-CF9E-XXX-993E-C71A8AED661E}
// *********************************************************************//
IWebBrowserBridgeDisp = dispinterface
['{4F995D09-CF9E-404XXXE-C71A8AED661E}']
procedure isAvailable; dispid 200;
procedure vibrate(ms: Integer); dispid 201;
end;
implementation
uses ComObj;
end.
对象库(类):
unit WebBrowserBridge;
interface
uses
// Delphi
ActiveX, SHDocVw, Windows, Classes, ComObj, Dialogs,
// Project
IntfDocHostUIHandler, UNulContainer, WebBrowserBridge_TLB;
type
TWebBrowserBridge = class(TAutoIntfObject, IWebBrowserBridge, IDispatch)
public
{ IMyExternal methods }
procedure isAvailable(); safecall;
procedure vibrate(ms: Integer); safecall;
public
constructor Create;
destructor Destroy; override;
end;
{
TWebBrowserBridgeContainer:
UI handler that extends browser's external object.
}
TWebBrowserBridgeContainer = class(TNulWBContainer, IDocHostUIHandler, IOleClientSite)
private
fExternalObj: IDispatch; // external object implementation
protected
{ Re-implemented IDocHostUIHandler method }
function GetExternal(out ppDispatch: IDispatch): HResult; stdcall;
public
constructor Create(const WBDefaultInterface: IDispatch);
end;
implementation
uses
SysUtils, StdActns;
{ TWebBrowserBridgeContainer }
constructor TWebBrowserBridgeContainer.Create(const WBDefaultInterface: IDispatch);
begin
inherited;
fExternalObj := TWebBrowserBridge.Create;
end;
function TWebBrowserBridgeContainer.GetExternal(out ppDispatch: IDispatch): HResult;
begin
ppDispatch := fExternalObj;
Result := S_OK; // indicates we've provided script
end;
{ TWebBrowserBridge }
constructor TWebBrowserBridge.Create;
var
TypeLib: ITypeLib; // type library information
ExeName: WideString; // name of our program's exe file
begin
// Get name of application
ExeName := ParamStr(0);
// Load type library from application's resources
OleCheck(LoadTypeLib(PWideChar(ExeName), TypeLib));
// Call inherited constructor
inherited Create(TypeLib, IWebBrowserBridge);
end;
destructor TWebBrowserBridge.Destroy;
begin
inherited;
end;
procedure TWebBrowserBridge.isAvailable();
begin
//Result:=1;
end;
procedure TWebBrowserBridge.vibrate(ms: Integer);
begin
windows.beep( 100, ms );
//showMessage( IntToStr( ms ));
end;
附言:
我也想知道如何在类型库中创建一个函数,因为它只允许创建过程或属性(但不支持像 Android 上的属性)。
编辑:
另请参阅我的回答,但由于上面的 PS,问题仍然悬而未决。
最佳答案
使用 ObjComAuto.TObjectDispatch 提供的后期绑定(bind)功能,可以使用更简单的方法在 Delphi 中实现 external
方法.
这样您就不需要定义任何接口(interface)或类型库。您所需要的只是一个实现所需事件的简单类,以及 $METHODINFO 提供的扩展 RTTI 信息。 .
您可以实现过程和函数,并接收 Delphi 类型或 javascript 对象作为参数。也可以从 Delphi 中使用 Javascript 对象(可以访问属性和方法)。
示例:(只需在表单中放置一个 TEmbeddedWB)
uses MSHTML_EWB, ObjComAuto;
type
{$METHODINFO ON} // activate detailed RTTI
TJavascriptReceiver = class
procedure MyMouseMove(event: variant);
procedure MyClick(event: variant);
function MyGet(msg: string): string;
end;
{$METHODINFO OFF}
{ TJavascriptReceiver }
procedure TJavascriptReceiver.MyMouseMove(event: variant);
begin
Form1.Caption := IntToStr(event.clientX) + ', ' + IntToStr(event.clientY);
end;
procedure TJavascriptReceiver.MyClick(event: variant);
var
w: variant;
begin
w := (Form1.EmbeddedWB1.Document as IHTMLDocument2).parentWindow;
w.testGet('Caption: ');
end;
function TJavascriptReceiver.MyGet(msg: string): string;
begin
Result := msg + Form1.Caption;
end;
{ TForm1 }
procedure TForm1.FormCreate(Sender: TObject);
var
strs: TStringStream;
begin
strs := TStringStream.Create;
try
strs.WriteString(
'<!DOCTYPE html>'
+'<html>'
+'<head>'
+' <style>'
+' html, body { margin: 0; padding: 0; height: 100%; }'
+' </style>'
+' <script>'
+' function testGet(msg) {'
+' alert(external.MyGet(msg));'
+' }'
+' </script>'
+'</head>'
+'<body'
+' onmousemove="external.MyMouseMove(event)"'
+' onclick="external.MyClick(event)"'
+'>'
+'Click anywhere'
+'</body>'
+'</html>'
);
EmbeddedWB1.LoadFromStream(strs);
finally
strs.Free;
end;
end;
procedure TForm1.EmbeddedWB1GetExternal(Sender: TCustomEmbeddedWB;
var ppDispatch: IDispatch);
begin
ppDispatch := TObjectDispatch.Create(TJavascriptReceiver.Create);
end;
注意:
Javascript arrays are sparse ,因此您无法使用通常的 myArray[3]
语法从 Delphi 访问它们。相反,您需要像使用索引一样使用索引,即某种 myArray.3
。这不是 Delphi 直接支持的,而是使用 ComObj.GetDispatchPropValue : GetDispatchPropValue(myArray, '3')
。更多信息 here .
编辑:
有关如何通过 window.external
方法进行迭代的信息,请参阅我的其他答案。
关于javascript - TEmbeddedWB/TWebbrowser : window. external 是一个空对象但是可以调用函数,为什么一开始是 'empty'?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/22165895/
如何更改 TEmbeddedWB 的默认背景颜色 (clWhite)组件同时不显示任何页面? 最佳答案 这可以通过在创建表单时加载默认页面来完成(快速方法): function ColorToHTML
Internet Explorer 10 内置了拼写检查器,并且运行良好。我尝试创建一个小型 HTML 页面来测试它,其中包含以下内容: Theze ara mispeled wordz 所
iam 尝试从图像 htmlTag 内的资源加载图像作为示例 我尝试做这样的事情 function getFullHTML(res:string):string; var sURL : stri
在 TEmbeddedWB 中的 iframe 内播放 Youtube 视频一直有效,但不幸的是现在它不再有效了。 Google 是否进行了更改以停止在具有嵌入式网络浏览器的程序中播放视频?我有以下简
在 Delphi VCL 窗体上放置一个 TMemo、一个 TEmbeddedWB 和一个 TButton。 这是来自表单单元的代码: procedure TForm1.Button1Click(Se
我试图阻止由 TEmbeddedWB 或 TWebBrowser(或 TCppWebBrowser)加载的任何外部内容。我想阻止从互联网加载的任何内容,包括图像、javascript、外部 CSS、外
我总体上对 TEditCut、TEditCopy、TEditPaste 和 TEditSelectAll 的功能感到满意,但它们不适用于任何非标准的控件。 例如,它们可能在 TEdit 或 TMemo
用例(先是一些信息): 我制作了一些 HTML/CSS3/Javascript 游戏,它们可以在特定于平台的可执行文件中的 WebView/嵌入式浏览器中的不同平台上运行。我自己设计了它,因为我厌倦了
故事:我开发了一款游戏,想要使用目标操作系统的 webview/嵌入式浏览器部署到许多平台。编写一次,部署多次;-) 游戏本身是使用 HTML5/CSS3 和 javascript 开发的,并且还为支
我是一名优秀的程序员,十分优秀!