网页和原生程序的交互方案

news2024/11/18 21:35:59

1 ActiveX和BHO是微软开发且闭源的,仅适用于IE

这里就不讨论了,这种方式会给用户带来很大的安全风险。而且也不符合html5标准,现在已经被市场抛弃。

2 搜索挂接(URL SEARCHHOOK)

在window系统中,通过在注册表中,写入相应的键值信息,来实现通过在浏览器中,通过url来打开本地原生程序的目的。此方法实现很简单,但是缺点也是很明显的,第一、每次调用都会弹出询问是否打开当前的可执行程序,如下图所示:

 第二、不能实现实时的交互,只能通过参数将外部进行带入一次;

具体的示例代码如下,网上到处都是这种代码,如果不够清除,可以自己去检索;

 int RegWebProtocol ( LPCTSTR lpszProtocolName, LPCTSTR lpszAssociatedApp, int nIconIndex/*=0*/ )
	{
		if ( !lpszProtocolName || 
			lstrlen(lpszProtocolName) < 1 || 
			!lpszAssociatedApp || 
			lstrlen(lpszAssociatedApp) < 1 )   
			return 0;

		CString csSubKey;
		DWORD dwBufSize = 0;

		// 如果该该协议已经存在
		HKEY hKey = NULL;
		if ( RegOpenKeyEx ( HKEY_CLASSES_ROOT,
			lpszProtocolName,
			0,
			KEY_ALL_ACCESS,
			&hKey ) == ERROR_SUCCESS )
		{
			RegCloseKey(hKey);

			csSubKey.Format ( _T("%s\\shell\\open\\command"), lpszProtocolName );
			
			CString csCommand; csCommand.Format ( _T("\"%s\" \"%%1\""), lpszAssociatedApp );
			dwBufSize = csCommand.GetLength();
			if ( !WriteRegister ( HKEY_CLASSES_ROOT, csSubKey,
				_T(""), REG_SZ, (PUCHAR)csCommand.GetBuffer(0),&dwBufSize) )
				return 0;
			return 2;
		}
		else 
			hKey = NULL;

		// 创建协议子键
		if (!CreateRegisterSubKey ( HKEY_CLASSES_ROOT, lpszProtocolName ))
			return 0;

		// 设置协议描述字符串
		CString csProtocolDesc; 
		csProtocolDesc.Format ( _T("%sProtocol"), lpszProtocolName );
		dwBufSize = csProtocolDesc.GetLength();
		if ( !WriteRegister ( HKEY_CLASSES_ROOT, lpszProtocolName,
			_T(""), REG_SZ, (PUCHAR)csProtocolDesc.GetBuffer(0),&dwBufSize) )
			return 0;
		CString csAppFile; csAppFile.Format ( _T("%s"), lpszAssociatedApp );
		dwBufSize = csAppFile.GetLength();
		if ( !WriteRegister ( HKEY_CLASSES_ROOT, lpszProtocolName,
			_T("URL Protocol"), REG_SZ, (PUCHAR)csAppFile.GetBuffer(0),&dwBufSize) )
			return 0;

		// DefaultIcon 子键
		csSubKey.Format ( _T("%s\\DefaultIcon"), lpszProtocolName );
		if ( !CreateRegisterSubKey ( HKEY_CLASSES_ROOT, csSubKey ) )
			return 0;
		CString csIconParameter; csIconParameter.Format ( _T("%s,%d"), lpszAssociatedApp, nIconIndex );
		dwBufSize = csIconParameter.GetLength();
		if ( !WriteRegister ( HKEY_CLASSES_ROOT, csSubKey,
			_T(""), REG_SZ, (PUCHAR)csIconParameter.GetBuffer(0),&dwBufSize) )
			return 0;

		// shell\open\command 子键
		csSubKey.Format ( _T("%s\\shell\\open\\command"), lpszProtocolName );
		if ( !CreateRegisterSubKey ( HKEY_CLASSES_ROOT, csSubKey ) )
			return 0;
		CString csCommand; csCommand.Format ( _T("\"%s\" \"%%1\""), lpszAssociatedApp );
		dwBufSize = csCommand.GetLength();
		if ( !WriteRegister ( HKEY_CLASSES_ROOT, csSubKey,
			_T(""), REG_SZ, (PUCHAR)csCommand.GetBuffer(0),&dwBufSize) )
			return 0;

		return 1;
	}

其中,HKEY_CLASSES_ROOT和HKEY_LOCAL_MACHINE\SOFTWARE\Classes是一样的。具体的原理是,The IURLSearchHook interface is used by the browser to translate the address of an unknown URL protocol.

 When attempting to browse to a URL address that does not contain a protocol,

 the browser will first attempt to determine the correct protocol from the address.

 If this is not successful, the browser will create URL Search Hook objects and call each object's

 Translate method until the address is translated or all of the hooks have been queried.

 IURLSearchHook接口被浏览器用来转换一个未知的URL协议地址。

 当浏览器企图去打开一个未知协议的URL地址时,浏览器首先尝试从这个地址得到当前的协议,如果不成功,浏览器将创建在系统中注册的URL Search Hook对象并调用每一个对象的Translate方法,直到地址被转换或所有的URL Search Hook都尝试过。 也就是说,我们可以注册一种目前不存在的协议(类似HTTP),当浏览器遇到新的协议时会自动调用Translate方法来翻译我们的协议, 甚至激活我们自己的程序。这里注意,改动注册表的时候,必须以管理员身份来运行;

 以下是调用的代码

 RegWebProtocol("YYP", "D:\\xxx\\测试源码\\SurfaceRender\\UrlCall\\Debug\\UrlCall.exe", 1);

 程序就会自动运行起来,运行的结果如下

 3. Chromium Embedded Framework (CEF)

其实,此方案也是用来解决BS和CS架构目前最优的方案,既可以利用BS中的所有优势,升级快,部署方便,另外,界面的开发速度也快,还能有界面的高还原度;又能对程序需要控制系统资源的需求得到满足。Adobe和微软的几款产品都是基于CEF开发的,足见此方案的分量。

英文帮助的文档 https://bitbucket.org/chromiumembedded/cef/wiki/GeneralUsage.md#markdown-header-entry-point-function

3.1 同源(origin)

origin = scheme(协议)+ domain(域名)+port(端口);例如,

url= "http://baidu.com:80/pub/new";  

origin = "http://baidu.com:80";  

CEF3 runs using multiple processes. The main process which handles window creation, painting and network access is called the “browser” process. This is generally the same process as the host application and the majority of the application logic will run in the browser process. Blink rendering and JavaScript execution occur in a separate “render” process. Some application logic, such as JavaScript bindings and DOM access, will also run in the render process. The default process model will spawn a new render process for each unique origin (scheme + domain). Other processes will be spawned as needed, such as “plugin” processes to handle plugins like Flash and “gpu” processes to handle accelerated compositing.

3.2 浏览器进程 Browser Process和渲染进程 Render Process

目前我的认知内,一个实例只有一个浏览器进程。它的作用有二。第一、负责通过CefBrowserHost::CreateBrowser函数来创建页面窗口,以及,对应的渲染进程和其他进程(插件进程和GPU进程等进程);第二、其他的进程向浏览器进程发送消息,进行通讯;我们可以定制不一样的回调句柄,来处理renderer process发送的信息;使用CefBrowserHost::CreateBrowser函数,为新的原点(origin)创建新的html的浏览器(CefBrowserView)和当前原生窗口绑定到一起(Windows系统,就是一个对话框或者Frame),另外,浏览器进程会接受子进程的消息回调,用来处理这些子进程的发出消息。回调的类,需要开发者自定义一个ClientHandler类用来继承一些Cef的接口,来处理渲染进程或其他进程发送来的标准回调消息;例如,处理子进程生命周期的回调函数,下载的回调等,例如,CefLifeSpanHandler,表示的是Implement this interface to handle events related to browser life span. The methods of this class will be called on the UI thread unless otherwise indicated. 当使用函数CefBrowserHost::CreateBrowser(info, m_handler.get(), strUrl, settings, NULL);来创建浏览器的时候,会调用CefLifeSpanHandler接口中的OnAfterCreated函数关闭的时候,会调用 OnBeforeClose函数

class ClientHandler 
	: public CefClient,
	public CefDownloadHandler,
	public CefLoadHandler,
	public CefLifeSpanHandler,
	public CefRenderHandler
{
// Include the default reference counting implementation.
    IMPLEMENT_REFCOUNTING(ClientHandler);
public:
	virtual void OnAfterCreated(CefRefPtr<CefBrowser> browser) OVERRIDE
	{
	}
	virtual void OnBeforeClose(CefRefPtr<CefBrowser> browser) OVERRIDE
	{
	}
	virtual CefRefPtr<CefDownloadHandler> GetDownloadHandler() OVERRIDE 
	{return this;
	}
	virtual CefRefPtr<CefLoadHandler> GetLoadHandler() OVERRIDE 
	{return this;
	}

	bool OnProcessMessageReceived(CefRefPtr<CefBrowser> browser,
                                CefProcessId source_process,
                                CefRefPtr<CefProcessMessage> message) OVERRIDE
	{
		ClientApp::RenderDelegateSet::iterator it = render_delegates_.begin();
		for (; it != render_delegates_.end(); ++it)
			(*it)->OnProcessMessageReceived(NULL, browser, source_process, message);
		return true;
	}

	virtual void OnPaint(CefRefPtr<CefBrowser> browser,
                       PaintElementType type,
                       const RectList& dirtyRects,
                       const void* buffer,
                       int width, int height)
	{
	}
};

3.3 CefFrame 和 CefBrowser

没一个CefBrowser都有一个主的CefFrame和0和多个子CefFrame,例如一个网页包含两个iFarme标签,就是一个主的CefFrame,两个子CefFrame对象;Each CefBrowser object will have a single main CefFrame object representing the top-level frame and zero or more CefFrame objects representing sub-frames. For example, a browser that loads two iframes will have three CefFrame objects (the top-level frame and the two iframes).

3.4 动态交互,进程间的通讯 Inter-Process Communication (IPC)

由于CEF3在多个进程中运行,因此有必要提供用于在这些进程之间进行通信的机制。CefBrowser和CefFrame对象同时存在于浏览器和渲染过程中,这样设计有助于进程间通讯。每个CefBrowser和CefFrame对象也有一个与其关联的唯一ID值,该值将在流程边界的两侧匹配。Since CEF3 runs in multiple processes it is necessary to provide mechanisms for communicating between those processes. CefBrowser and CefFrame objects exist in both the browser and render processes which helps to facilitate this process. Each CefBrowser and CefFrame object also has a unique ID value associated with it that will match on both sides of the process boundary. 进程间的消息可以通过CefProcessMessage来实现,示例如下

// Create the message object.
CefRefPtr<CefProcessMessage> msg= CefProcessMessage::Create(“my_message”);
// Retrieve the argument list object.
CefRefPtr<CefListValue> args = msg>GetArgumentList();
// Populate the argument values.
args->SetString(0, “my string”);
args->SetInt(0, 10);
// Send the process message to the main frame in the render process.
// Use PID_BROWSER instead when sending a message to the browser process.
browser->GetMainFrame()->SendProcessMessage(PID_RENDERER, msg);

一个从Browser进程发送到渲染进程的消息,是通过CefRenderProcessHandler::OnProcessMessageReceived()来实现的;反过来,从渲染进行到浏览器进程是通过CefClient::OnProcessMessageReceived().函数来实现回调的。A message sent from the browser process to the render process will arrive in CefRenderProcessHandler::OnProcessMessageReceived(). A message sent from the render process to the browser process will arrive in CefClient::OnProcessMessageReceived().

 4 通过websocket的方式

4.1 websocket原理介绍

通过CEF的方式,实现js和原生程序交互,是一个绝佳的方案。但同样具有缺点,即不能和通用浏览器(Chrome,Edge)中的页面(js),实现实时的交互。可以实时交互,都是基于页面在二次开发的程序中进行打开的前提下,才能成立。此时WebSocket就是另外一个绝佳的方案,可以用它来实现浏览器中的js和原生程序之间的通讯,且没有http跨域访问的问题。

实际上,websocket和socket是一样的,只是在accept后,需要去验证,当前链接的socket收到的请求信息(请求头),是否符合websocket协议。客户端发送来的链接信息头,如下格式所示,以下代码中的换行都是用\r\n隔开,整个头结束是\r\n\r\n来结束。所有的信息格式的验证都是通过自己写代码来实现的。

GET / HTTP/1.1
Host: localhost:10010
Connection: Upgrade
Pragma: no-cache
Cache-Control: no-cache
User-Agent: Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/112.0.0.0 Safari/537.36 Edg/112.0.1722.64
Upgrade: websocket
Origin: null
Sec-WebSocket-Version: 13
Accept-Encoding: gzip, deflate, br
Accept-Language: zh-CN,zh;q=0.9,en;q=0.8,en-GB;q=0.7,en-US;q=0.6
Sec-WebSocket-Key: Nehn10clcDKqzQ69hrsxOw==
Sec-WebSocket-Extensions: permessage-deflate; client_max_window_bits

返回信息头

HTTP/1.1 101 Switching Protocols
Upgrade: websocket
Connection: upgrade
Sec-WebSocket-Accept: fmZxN7gu1bI/ZfLrHITOcm33JJQ=

4.2 websoket示例代码

这里代码很多,就不单独用代码块来列举了。这里的代码是vs2012的工程。其中最重要的两个函数是ListeningSocketMethod,在此函数中,是监听socket不断的监听前来链接的socket;EstablishSocketMethod,在此函数中,是已经处理链接完成的socket信息函数;

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/502860.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

3.1 Linux启动Shell

系列文章目录 第1章 Linux Shell简介 第2章 Shell基础 第3章 Bash Shell基础命令 <本章所在位置> 第4章 Bash Shell命令进阶 第5章 Linux Shell深度理解 第6章 Linux环境变量 第7章 Linux文件权限 第8章 Linux文件系统的管理 第9章 Linux软件安装 第10章 Linux文本编辑器…

框架不是框框—应用框架的基本思想

软件构件化是21世纪软件工业发展的大势趋。工业化的软件复用已经从通用类库进化到了面向领域的应用框架。Gartner Group认为&#xff1a;“至少70%的新应用将主要建立在如软件构件和应用框架这类‘构造块’之上&#xff1b;应用开发的未来就在于提供一开放体系结构&#xff0c;…

http状态码301、302及304

http状态码分类&#xff1a; 1**&#xff1a;服务器收到请求&#xff0c;需要请求者继续执行操作 2**&#xff1a;成功&#xff0c;操作被成功接收并处理 3**&#xff1a;重定向&#xff0c;需要进一步的操作以完成请求 4**&#xff1a;客户端错误&#xff0c;请求包含语法错误…

Meta内容总监:Quest最初并非侧重游戏,VR用户画像每年都在变

2019年&#xff0c;随着Oculus Quest的发布&#xff0c;Quest应用商店应运而生。仅仅4年时间&#xff0c;就成为了发展速度最快的VR平台&#xff0c;吸引越来越多的开发者进入到Quest中去&#xff0c;并关注到VR生态。截至去年10月&#xff0c;Quest商店交易规模达15亿美元&…

云计算运维工程师好学吗?

云计算运维工程师作为2023年的热门IT职业之一&#xff0c;不仅在专业本身的技术内容和职业前景&#xff0c;还是整个互联网行业&#xff0c;乃至全行业对于云计算运维人才的需求等方面都有突出的表现&#xff0c;备受追捧的新IT职业。 所以从职业前景还是就业需求&#xff0c;…

2023年第一季度企业邮箱安全性观察

近日&#xff0c;Coremail邮件安全联合中睿天下发布《2023年第一季度企业邮箱安全研究报告》&#xff0c;对2023年第一季度的企业邮箱的安全风险进行了分析。 01、垃圾邮件环比增长21.19% 2023年Q1全国企业邮箱用户共收到各类垃圾邮件7.13亿封&#xff0c;相比2022年Q4季度环比…

SeaweedFS学习笔记:Filer服务,目录与文件

文章目录 1. 介绍2. 用法2.1 生成配置文件2.2 启动 filer 3. 读写流程3.1 读取流程3.2 写入流程 4. Filer Store4.1 复杂度4.2 Filer的使用场景 5. 数据加密5.1 对Volume server的数据进行加密 1. 介绍 文件系统&#xff0c;一般都离不开目录和文件&#xff0c;当我们把Seawee…

MySQL基础(十四)视图

1. 常见的数据库对象 对象描述表(TABLE)表是存储数据的逻辑单元&#xff0c;以行和列的形式存在&#xff0c;列就是字段&#xff0c;行就是记录数据字典就是系统表&#xff0c;存放数据库相关信息的表。系统表的数据通常由数据库系统维护&#xff0c;程序员通常不应该修改&…

K_A36_002 基于STM32等单片机驱动继电器点灯 串口与OLED0.96双显示

K_A36_002 基于STM32等单片机驱动继电器点灯 串口与OLED0.96双显示 所有资源导航一、资源说明二、基本参数参数引脚说明 三、驱动说明模块工作原理:对应程序: 四、部分代码说明1、接线引脚定义1.1、STC89C52RC继电器模块1.2、STM32F103C8T6继电器模块 五、基础知识学习与相关资…

在学习c51单片机实验七(双机通信及pcb设计)操作Keil uVision4和protus的时候遇到的两个坑

第一个问题&#xff0c;这个问题用keil编程经常遇到 特别是懒的时候&#xff0c;对于新手&#xff0c;每次用一个工程文件&#xff0c;因为创建不熟练&#xff0c;就容易出现这个问题 Build target Target 1 linking... *** ERROR L104: MULTIPLE PUBLIC DEFINITIONS SYM…

FPGA通过数码管实现电子时钟

文章目录 前言一、原理1、共阴极数码管or共阳极数码管2、共阴极与共阳极的真值表 二、系统设计1、总体框图&#xff1a;2、模块调用3、模块原理图 三、源码1、计数模块2、数码管驱动模块3、顶层模块 四、运行效果五、总结六、参考资料 前言 环境&#xff1a; 1、Quartus18.1 2、…

cloud在gateway支持https和http请求

在项目中遇到既要支持http协议请求和https协议请求的场景&#xff0c;结合场景有两种解决方案&#xff1a; 第一种&#xff1a;编程实现&#xff0c;第二种&#xff1a;反向代理。 首先我们要清楚http和https的区别&#xff0c;百度过来一点 HTTP&#xff08;HTTP&#xff0…

目标检测之Neck选择

文章来自于&#xff1a;曲終人不散丶知乎&#xff0c; 连接&#xff1a;https://www.zhihu.com/people/qu-zhong-ren-bu-san-zhu-45/posts&#xff0c; 本文仅用于学术分享&#xff0c;如有侵权&#xff0c;前联系后台做删文处理。 Neck是目标检测框架中承上启下的关键环节。它…

Golang Gin 多数据格式返回请求结果

下面介绍返回类型如下&#xff1a; [ ]byte和stringJSON格式HTML模板渲染静态资源设置 背景 在前面的课程中&#xff0c;我们已经学习和掌握了多类型的网络请求和处理&#xff0c;还掌握了提交数据与结构体绑定的操作。我们都知道&#xff0c;一个完整的请求包含请求、处理请求…

掌握Linux操作系统:一步步引导您成为Linux专家

Linux是一种流行的操作系统&#xff0c;我们可以在服务器、桌面电脑和移动设备上使用它。基本的Linux知识可以帮助您理解操作系统如何工作&#xff0c;以及如何为您的计算机提供安全和可靠的环境。下面是一些方法&#xff0c;可以帮助您学习Linux&#xff1a; 安装Linux操作系统…

4月京东生鲜水果行业数据报告:榴莲销量增长400%,市场格局剧变

众所周知&#xff0c;今年水果领域的一个重磅消息就是&#xff1a;榴莲价格暴跌。目前全国多地线下水果专卖店、农贸市场的榴莲价格都在下滑&#xff0c;有的地区在4月底甚至已经降至最低每斤20元左右。预测在5月的销售旺季&#xff0c;价格还有望一路向下。 •榴莲逆袭苹果&am…

二十一、线索转换2:线索公司信息到客户表,线索中个人信息到联系人

功能需求 1.线索的关联公司信息--》客户表 2.线索的个人信息--》联系人 3.线索的公司备注信息--》客户备注 4.线索的个人信息---》联系人备注 5.线索-市场 --> 联系人和市场 6.创建交易&#xff0c;交易表添加记录 7.创建交易&#xff0c;线索的备注-->交易备注 …

JMeter自动化压力测试-http

下载&#xff1a; Apache JMeter - Download Apache JMeterhttps://jmeter.apache.org/download_jmeter.cgi 安装&#xff1a; JDK 版本要求为 1.8。 一、Jmeter 介绍 1.1、Jmeter 有什么样功能 Apache JMeter 是一个开源、纯 Java、优秀的性能测试工具 能够测试许多不同的应…

lua | 运算符与字符串

目录 一、运算符 算数运算符 关系运算符 逻辑运算符 其他运算符 运算符优先级 二、字符串 转义字符 方法与用途 字符串截取 字符串大小转换 字符串查找与反转 字符串格式化 字符与整数的转换 匹配模式 本文章为笔者学习分享 学习网站&#xff1a;Lua 基本语法 | …

分享三种高效的方法,快速将一个PDF文件分割成两个!

如何将一个PDF分割成两个&#xff1f;PDF文件在学习和工作中都是常用的文件格式&#xff0c;但是有时候我们可能只需要其中的一部分内容&#xff0c;这时候就需要将PDF文件分割成两个或多个。本文将分享三种不同的方法&#xff0c;供大家参考。 一、使用在线工具分割 记灵在线…