我正在尝试修改 TChromium 的用户代理,但如果它使用 CefVCL,我发现没有任何程序。已经通过ceflib看起来必须是的,我看到一个变量“设置”接收一个值“user_agent”但是VCL已经有,会有还是不可能这样?
7 回答
没有内置的方法可以做到这一点。根据我的经验,用户代理设置什么都不做。所以你必须直接编辑ceflib.pas(第~8532行)才能达到这个效果。
settings.user_agent := cefstring(UserAgent);
变成:
settings.user_agent := cefstring('My USERAGENT v1.0');
使用上述内容,您可能希望包含您自己的操作系统和浏览器信息,因为这会阻止 CEF 对这些变量的实现。或附加它,如下所示:
settings.user_agent := cefstring(UserAgent+'; My UserAgent v1.0');
我就是这样做的.. 我已经使用 DCEF1 和 DCEF3 工作了大约一年.. 并且仍在学习!
查看demo guiclient的项目源码
begin
//CefCache := 'cache';
CefCache:='./ca1';
CefUserAgent:='"Mozilla/5.0(Linux; U; Android 4.0.4; zh-cn; MI-ONE C1 Build/IMM76D) UC AppleWebKit/534.31 (KHTML, like Gecko) Mobile Safari/534.31"';
CefOnRegisterCustomSchemes := RegisterSchemes;
CefSingleProcess := False;
if not CefLoadLibDefault then
Exit;
CefRegisterSchemeHandlerFactory('local', '', False, TFileScheme);
Application.Initialize;
Application.CreateForm(TMainForm, MainForm);
Application.Run;
end.
ceflib.pas 第 5549 行
Var
UA: integer;
UAescojido: Ustring;
...
settings.cache_path := CefString(Cache);
UA:= Random(2)+1; //NEW LINE
if UA=1 then UAescojido:= 'xxxxxxxxxx'; //NEW LINE
if UA=2 then UAescojido:= 'xxxxxxxxxx'; //NEW LINE
settings.user_agent := cefstring(UAescojido); //ASSIGN VARIABLE
没有完全改变,但它对我有用。
procedure TForm1.Chromium1BeforeResourceLoad(Sender: TObject;
const browser: ICefBrowser; const frame: ICefFrame;
const request: ICefRequest; const callback: ICefRequestCallback; out
Result: TCefReturnValue);
Var
map: ICefStringMultimap;
begin
map := TCefStringMultimapOwn.Create;
request.GetHeaderMap(map);
map.Append('User-Agent','Mozilla/5.0 (iPhone; U; CPU iPhone OS 3_0 like Mac OS X; en-us) AppleWebKit/528.18 (KHTML, like Gecko) Version/4.0 Mobile/7A341 Safari/528.16');
request.SetHeaderMap(map);
callback.Cont(true);
end;
在主程序单元的初始化部分设置 CefUserAgent 变量。
initialization
CefUserAgent := "Your Agent";
选择:
如果您使用的 CEF 版本没有 CefUserAgent 全局变量,那么您可以尝试:
用户代理存储在
var
settings: TCefSettings;
在局部函数中声明的ceflib文件中,而不是全局变量。设置记录包含一个可以修改的变量settings.user_agent 。
function CefLoadLib
是声明变量的地方,CefLoadLibDefault 调用 CefLoadLib。
在单元文件的顶部将设置设置为全局而不是将其保留为局部函数变量,这可能是一种解决方案,这样您就可以在组件加载到表单之前修改另一个单元的初始化部分中的用户代理。然而,由于在许多情况下全局变量是一件坏事,并且可能导致意想不到的后果......人们必须检查以确保进行这样的修改不会不安全。
如果还没有这样做,这应该是一个特性请求,要求 CEF for delphi 包含可在 vcl 组件中修改的用户代理设置。有没有人要求这个功能......然而......如果没有,它肯定会有用。
另一个临时解决方案是创建一个全局字符串变量,而不是整个设置记录都是全局的,并且在设置用户代理时只使用全局字符串变量:
settings.user_agent := cefstring(YourGlobalVariableHere);
这又不是一个永久的解决方案,这个特性应该真正在组件本身中实现。
我们已经使用 DCEF1 好几年了,我们还没有升级到 DCEF3(因为它缺少我们需要的东西)。所以这个答案可能已经过时了,但它的价值:
在 DCEF1 的 ciflib 单元中有一个名为 CefUserAgent 的全局变量。我们在我们的一个项目单元的初始化部分将该变量设置为我们的客户用户代理字符串。这很简单,似乎对我们很有效。
CefUserAgent := OutCustomUserAgentString;
我现在不记得这个方法的派生了(那是很久以前的事了),但我希望我们只会在单元的初始化部分完成它,如果这是使它正常工作所必需的。
不幸的是,我不知道这在 DCEF3 中是否仍然有效。
我的 (C++) 实现分叉 CEF 并将以下方法添加到 CefRequestHandler:
virtual bool GetOverrideUserAgent(CefRefPtr<CefBrowser> browser,
CefRefPtr<CefDictionaryValue> request_info,
CefString& overrideUserAgent) { return false; }
然后,在 cef\libcef\common\request_impl.cc 中:
void CefRequestImpl::Set(net::URLRequest* request) {
base::AutoLock lock_scope(lock_);
CHECK_READONLY_RETURN_VOID();
...
const content::ResourceRequestInfo* info =
content::ResourceRequestInfo::ForRequest(request);
if (info) {
...
CefRefPtr<CefBrowserHostImpl> browser =
CefBrowserHostImpl::GetBrowserForRequest(request);
if(browser) {
...
CefString overrideUserAgent;
if(request_handler->**GetOverrideUserAgent**(browser.get(),
request_info, overrideUserAgent)) {
headermap_.erase(
net::HttpRequestHeaders::kUserAgent);
headermap_.insert(
std::make_pair(net::HttpRequestHeaders::kUserAgent,
overrideUserAgent));
}
...
因此(基本)步骤如下: 1. fork CEF 2. 添加 CefRequestHandler::GetOverrideUserAgent 3. 在您的应用程序中,客户端处理程序应从 CefRequestHandler 派生并实现 GetOverrideUserAgent 4. 您的应用程序可以根据需要设置 UA。
然而,这就是我的做法。它可能不适合您的需求。