PPAPI插件与浏览器的通信
PPAPI的插件,原本是能够使用JS与浏览器交互的,https://code.google.com/p/ppapi/wiki/InterfacingWithJavaScript。这里还提供了一个JS与plugin交互的文档,但如今说不支持了。如今应该通过PPB_Messaging接口来完毕Plugin和浏览器的交互,详细參考 revision=92312&view=markup">https://src.chromium.org/viewvc/chrome/trunk/src/ppapi/c/ppb_messaging.h?revision=92312&view=markup
我实验了一下。通了。
Messaging接口非常好。传递的消息能够自已定义。类型也无限制。非常方便。
foruok原创。如需转载请关注foruok的微信订阅号“程序视界”联系foruok。
使用postMessage通信
Messaging接口与其他大多数接口一样,分PPB和PPP两側。
分开来说明一下要做的事情。
插件側
要做这么些事情:
- 实现PPP_Messaging接口。关键是void (*HandleMessage)(PP_Instance instance, struct PP_Var message)方法
- 在Get_Interface中返回名字是PPP_MESSAGING_INTERFACE的接口
- 在PPP_InitializeModule中获取 PPB_Messaging、PPB_Var、PPB_VarArray、PPB_VarDictionary等接口。
PPB_Messaging的PostMessage用于向浏览器发送消息。发送过去的消息,JS代码能够接收到。PPB_Var能够用来构造String类型的Var。能够操作Var的引用计数
PPB_VarArray是数组接口,能够创建、訪问、设置数组
PPB_VarDictionary是字典(map)接口。能够创建字典Var,能够存取key-value对。 - PPP_Messaging的HandleMessage处理浏览器的消息,假设须要。调用PPB_Messaging的PostMessage发送消息.
注意,插件側调用PPB_Var接口的VarFromUtf8时,传入的len不包含’\0’在内。PPAPI的ppb_var.h的凝视里的演示样例代码片段有误,调用时传递的长度是sizeof(hello_world)。应该减去一。
另一点,插件和浏览器交互的数据。都是数据的拷贝哦,调用接口会发生复制行为。
浏览器側
浏览器側能够使用JavaScript来监听插件发送的message事件,也能够使用插件元素的postMessage发送消息给插件。
基本上做以下几件事就可以:
- 实现处理消息的JS函数,其參数是MessageEvent。data成员为插件发过来的信息,能够当做JS对象来訪问。
- 监听插件的message事件
- 在合适的时候调用插件的postMessage(object)方法发送消息给插件
代码
分插件代码和HTML代码。
插件代码
代码是在在PPAPI插件中创建本地窗体一文演示样例代码的基础上改的。加入了消息处理的部分。仅仅贴相关的部分了。
获取消息相关接口的代码
在PPP_InitializeModule中加入了获取PPB_Messaging接口以及其他可能用到的PP_Var类型的接口。有Array和Dictionary。
g_var_interface = (const PPB_Var*)get_browser_interface(PPB_VAR_INTERFACE);
g_dictionary_interface = (const PPB_VarDictionary*)get_browser_interface(PPB_VAR_DICTIONARY_INTERFACE);
g_array_interface = (const PPB_VarArray*)get_browser_interface(PPB_VAR_ARRAY_INTERFACE);
g_message_interface = (const PPB_Messaging*)get_browser_interface(PPB_MESSAGING_INTERFACE);
PPP_Messaging接口的实现
PPP_Messaging接口的实现代码例如以下:
void Plugin_HandleMessage(PP_Instance instance, struct PP_Var message)
{
char szLog[256] = { 0 };
sprintf_s(szLog, 256, "Plugin_HandleMessage, type = %d\r\n", message.type);
OutputDebugStringA(szLog);
if (message.type == PP_VARTYPE_DICTIONARY)
{
char command[] = "command";
struct PP_Var commandKey = g_var_interface->VarFromUtf8(command, sizeof(command) - 1);
struct PP_Var commandVar = g_dictionary_interface->Get(message, commandKey);
int len = 0;
const char *strCommand = g_var_interface->VarToUtf8(commandVar, &len);
g_var_interface->Release(commandKey);
sprintf_s(szLog, 256, "Plugin_HandleMessage, dict, command = %s, len = %d\r\n", strCommand, len);
OutputDebugStringA(szLog);
if (len == 0)
{
OutputDebugString(_T("Tang_plugin, recv invalid command\r\n"));
g_var_interface->Release(commandVar);
return;
}
if (strncmp(strCommand, "joinConf", len) == 0)
{
char confIdKey[] = "confId";
char userNameKey[] = "userName";
char *szConfId = 0;
char*szUserName = 0;
struct PP_Var idKey = g_var_interface->VarFromUtf8(confIdKey, sizeof(confIdKey) - 1);
struct PP_Var userKey = g_var_interface->VarFromUtf8(userNameKey, sizeof(userNameKey) - 1);
struct PP_Var var = g_dictionary_interface->Get(message, idKey);
const char *value = g_var_interface->VarToUtf8(var, &len);
if (len > 0)
{
szConfId = malloc(len + 1);
strncpy_s(szConfId, len+1, value, len);
szConfId[len] = 0;
}
g_var_interface->Release(var);
var = g_dictionary_interface->Get(message, userKey);
value = g_var_interface->VarToUtf8(var, &len);
if (len > 0)
{
szUserName = malloc(len + 1);
strncpy_s(szUserName, len+1, value, len);
szUserName[len] = 0;
}
g_var_interface->Release(var);
sprintf_s(szLog, 256, "Plugin_HandleMessage, dict, command = joinConf, user = %s, confId = %s\r\n", szUserName, szConfId);
OutputDebugStringA(szLog);
if (szConfId && szUserName)
{
sprintf_s(szLog, 256, "plugin got confId - %s, user - %s\r\n", szConfId, szUserName);
OutputDebugStringA(szLog);
joinConf(szConfId, szUserName);
}
else
{
OutputDebugString(_T("Invalid conference id or userName\r\n"));
}
if (szConfId) free(szConfId);
if (szUserName) free(szUserName);
g_var_interface->Release(idKey);
g_var_interface->Release(userKey);
/* fake attendees*/
char szMsgTypeValue[] = "userlist";
char szTypeKey[] = "type";
struct PP_Var typeKey = g_var_interface->VarFromUtf8(szTypeKey, sizeof(szTypeKey) - 1);
struct PP_Var typeValue = g_var_interface->VarFromUtf8(szMsgTypeValue, sizeof(szMsgTypeValue) - 1);
struct PP_Var attendee = g_dictionary_interface->Create();
g_dictionary_interface->Set(attendee, typeKey, typeValue);
struct PP_Var userArray = g_array_interface->Create();
char szUser1[] = "ZhangSan";
char szUser2[] = "LiSi";
struct PP_Var user1 = g_var_interface->VarFromUtf8(szUser1, sizeof(szUser1) - 1);
struct PP_Var user2 = g_var_interface->VarFromUtf8(szUser2, sizeof(szUser2) - 1);
g_array_interface->Set(userArray, 0, user1);
g_array_interface->Set(userArray, 1, user2);
char szValueKey[] = "value";
struct PP_Var valueKey = g_var_interface->VarFromUtf8(szValueKey, sizeof(szValueKey) - 1);
g_dictionary_interface->Set(attendee, valueKey, userArray);
g_message_interface->PostMessage(instance, attendee);
OutputDebugString(_T("Post attendee to browser"));
g_var_interface->Release(typeKey);
g_var_interface->Release(typeValue);
g_var_interface->Release(user1);
g_var_interface->Release(user2);
g_var_interface->Release(valueKey);
g_var_interface->Release(userArray);
g_var_interface->Release(attendee);
}
else if (strncmp(strCommand, "viewVideo", len) == 0)
{
char userIdKey[] = "userId";
char *szUserId = 0;
struct PP_Var idKey = g_var_interface->VarFromUtf8(userIdKey, sizeof(userIdKey) - 1);
struct PP_Var var = g_dictionary_interface->Get(message, idKey);
const char *value = g_var_interface->VarToUtf8(var, &len);
if (len > 0)
{
szUserId = malloc(len + 1);
strncpy_s(szUserId, len + 1, value, len);
szUserId[len] = 0;
}
if (szUserId)
{
sprintf_s(szLog, 256, "plugin got userId - %s\r\n", szUserId);
OutputDebugStringA(szLog);
viewVideo(szUserId, g_child_window);
}
else
{
OutputDebugString(_T("Invalid viewVideo command without userId\r\n"));
}
if (szUserId) free(szUserId);
g_var_interface->Release(var);
g_var_interface->Release(idKey);
}
g_var_interface->Release(commandVar);
}
else if (message.type == PP_VARTYPE_STRING)
{
char hello_world[] = "Hello world!";
struct PP_Var var = g_var_interface->VarFromUtf8(hello_world, sizeof(hello_world) - 1);
g_message_interface->PostMessage(instance, var); // var will be copyed
g_var_interface->Release(var);
}
}
static PPP_Messaging message_interface = {
&Plugin_HandleMessage
};
有点长,比較潦草。
返回PPP_Messaging的代码
完整的PPP_GetInterface函数例如以下:
PP_EXPORT const void* PPP_GetInterface(const char* interface_name) {
if (strcmp(interface_name, PPP_INSTANCE_INTERFACE) == 0)
{
OutputDebugString(_T("PPP_GetInterface, instance_interface\r\n"));
return &instance_interface;
}
else if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)
{
OutputDebugString(_T("PPP_GetInterface, input_interface\r\n"));
return &input_interface;
}
else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0)
{
OutputDebugString(_T("PPP_GetInterface, message_interface\r\n"));
return &message_interface;
}
return NULL;
}
网页代码
网页代码例如以下:
<!DOCTYPE html>
<html>
<!--
Copyright (c) 2016 foruok@微信订阅号“程序视界”(programmer_sight).
All rights reserved.
Use of this source code is governed by a BSD-style license that can be
found in the LICENSE file.
-->
<head>
<style type="text/css">
#contacts
{
margin: 10px;
width: 300px;
height: 200px;
background-color: gray;
}
</style>
<script type="text/javascript">
function handleMessage(message) {
alert(message.data.type);
if(message.data.type.localeCompare("userlist") == 0){
var i = 0;
ul = document.getElementById("attendee");
for(; i < message.data.value.length; i++){
var li = document.createElement("li");
li.appendChild(document.createTextNode(message.data.value[i]));
ul.appendChild(li);
}
}
}
function joinConference(){
plugin = document.getElementById('tangplugin');
plugin.postMessage({
command:"joinConf",
confId: document.getElementById("confId").value,
userName: document.getElementById("userName").value
});
}
function viewSharedVideo(){
plugin = document.getElementById('tangplugin');
plugin.postMessage({
command:"viewVideo",
userId: document.getElementById("userId").value
});
}
function initialize() {
plugin = document.getElementById('tangplugin');
plugin.addEventListener('message', handleMessage, false);
}
document.addEventListener('DOMContentLoaded', initialize, false);
</script>
<title>Tang in Plugin</title>
</head>
<body>
<form>
ConferenceID: <input type="text" id="confId" /> User:
<input type="text" id="userName" /> <input type="button" value="Join" onclick="joinConference()"/>
</form>
<hr>
<div id="contacts">
<p>contacts:</p>
<ul id="attendee">
<!--
here will show attendee list, added by JS callback
-->
</ul>
UserId:<input type="text" id="userId" /> <button type="button" onclick="viewSharedVideo()">View Video</button>
</div>
<p>share video:</p>
<embed id="tangplugin" type="application/x-ppapi-tang-video" width="300px" height="200px" top="40px" left="20px">
</body>
</html>
Join按钮会获取它前面两个文本框的内容。发送给插件。插件返回一个用户列表,网页解析(HandleMessage方法)出来,动态改动用户列表。
执行效果
贴两幅图,点击Join按钮之前是酱紫的:
点击Join按钮后是酱紫的:
其他參考文章:
PPAPI插件与浏览器的通信的更多相关文章
- PPAPI插件的全屏切换处理
有时你会想让PPAPI插件全屏(比方播放视频时),这次来看看怎么做. PPAPI和CEF App两側都要处理. foruok原创,转载请注明出处.欢迎关注foruok的订阅号"程序视界&qu ...
- PPAPI插件的动态创建、改动、删除
一旦你完毕了PPAPI插件的开发,实际使用时可能会有下列需求: 动态创建PPAPI插件 删除PPAPI插件 改变PPAPI插件的尺寸 实现起来非常easy,从JS里直接訪问DOM(BOM)就可以.以下 ...
- Python+selenium 自动化-启用带插件的chrome浏览器,调用浏览器带插件,浏览器加载配置信息。
Python+selenium 自动化-启用带插件的chrome浏览器,调用浏览器带插件,浏览器加载配置信息. 本文链接:https://blog.csdn.net/qq_38161040/art ...
- VLC Web插件的浏览器兼容性
网页插件实现原理 IE浏览器基于Activex插件来实现,非IE浏览器采用NPAPI来实现,所以,非浏览器需要支持NPAPI来实现. IE浏览器 FF浏览器(版本小于52) 原因从 Firefox 版 ...
- Web跨浏览器进程通信(Web跨域)
Web跨域已是老生常谈的话题,这次来尝试下跨域浏览器进程之间的通信 —— 这在过去基本依靠网络中转实现 在之前一篇文章里尝试了跨浏览器的数据共享,最后提到使用LocalConnection还可以实 ...
- ssm项目中KindEditor的图片上传插件,浏览器兼容性问题
解决办法: 原因:使用@ResponseBody注解返回java对象,在浏览器中是Content-Type:application/json;charset=UTF-8 我们需要返回字符串(Strin ...
- sublime3下载安装及常用插件、浏览器预览设置
之前与学习前端有关的软件都安装在了实验室电脑上,最近由于要放寒假(也许我寒假回去会学习呢),于是得在笔记本电脑上重新安装一遍.几个软件各种出错,花了一下午才安装好,必须记录下来啊! 这篇文章主要介绍s ...
- 解决uploadify插件不同浏览器下的兼容性问题
http://www.thinkphp.cn/code/2138.html uploadify在部分浏览器上没法使用,或者各种报错的解决方法.uploadify插件上传图片是很爽的体验. 如果用chr ...
- 十四、.net core(.NET 6)搭建ElasticSearch(ES)系列之给ElasticSearch添加SQL插件和浏览器插件
给ES添加SQL插件的方法: 下载SQL插件地址:https://github.com/NLPchina/elasticsearch-sql 当前最新的是7.12版本,我的ES是7.13版本,暂且将 ...
随机推荐
- SUSE glibc升级为2.18过程记录
先验知识:1.运行时,动态库的装载依赖于ld-linux.so.6的实现,它查找共享库的顺序如下:(1)ld-linux.so.6在可执行的目标文件中被指定,可用readelf命令查看(2)ld-li ...
- 【POJ 1830】 开关问题
[题目链接] http://poj.org/problem?id=1830 [算法] 列出异或方程组,用高斯消元求解 [代码] #include <algorithm> #include ...
- yii依赖注入
为了降低代码耦合程度,提高项目的可维护性,Yii采用多许多当下最流行又相对成熟的设计模式,包括了依赖注入(Denpdency Injection, DI)和服务定位器(Service Locator) ...
- c语言return与exit的区别
2013-09-0918:54:33 exit函数在头文件stdlib.h中,函数原型: void exit(int status); exit(0) 正常运行程序并退出程序. exit(1) 非正常 ...
- JavaScript命名空间的理解与实现
命名空间有效防止函数名/类名和其他人的冲突,在使用多个第三方框架或类库的时候,一旦冲突,唯一能作的就是放弃其中一个.从事Web开发不可避免要接触JavaScript,目前最新版本的JavaScript ...
- docker应用栈实践-nginx处理静态文件
在我的djangoweb应用在docker搭建好之后,发现一些css静态文件返回没有content-type属性,导致浏览器log一堆警告,强迫症的我受不了这一情况 目前的应用栈结构图: 一共四个容器 ...
- 经典C/S服务器模型之守护进程
linux编程-守护进程编写 守护进程(Daemon)是运行在后台的一种特殊进程.它独立于控制终端并且周期性地执行某种任务或等待处理某些发生的事件.守护进程是一种很有用的进程. Linux的大多数服务 ...
- ubuntu 安装 OpenCV-CUDA
参考链接:http://www.cnblogs.com/platero/p/3993877.html 官方指导:https://help.ubuntu.com/community/OpenCV 0.这 ...
- 开发一款合格的APP成本费用大概是多少?
随着移动互联网的发展,APP开发已经成了当下最热门的话题.无数人都盼望做出下一个微信.滴滴打车等等神奇的APP软件.如今,APP开发门槛已经非常低,媒体上也充斥着各种小团队创造奇迹的故事.不过,APP ...
- ZBrush 2018软件安装激活教程一点通
Zbrush下载地址:https://pixologic.com/CD 安装教程:(此CD代码仅有效一次,一旦此代码被使用,您将收到一封包含你账户信息的电子邮件.请把那封电子邮件保存在你的记录里.) ...