• PPAPI插件与浏览器的通信


    PPAPI的插件,原本是能够使用JS与浏览器交互的,https://code.google.com/p/ppapi/wiki/InterfacingWithJavaScript。这里还提供了一个JS与plugin交互的文档,但如今说不支持了。如今应该通过PPB_Messaging接口来完毕Plugin和浏览器的交互,详细參考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两側。

    分开来说明一下要做的事情。

    插件側

    要做这么些事情:

    1. 实现PPP_Messaging接口。关键是void (*HandleMessage)(PP_Instance instance, struct PP_Var message)方法
    2. 在Get_Interface中返回名字是PPP_MESSAGING_INTERFACE的接口
    3. 在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对。

    4. PPP_Messaging的HandleMessage处理浏览器的消息,假设须要。调用PPB_Messaging的PostMessage发送消息.

    注意,插件側调用PPB_Var接口的VarFromUtf8时,传入的len不包含’’在内。PPAPI的ppb_var.h的凝视里的演示样例代码片段有误,调用时传递的长度是sizeof(hello_world)。应该减去一。

    另一点,插件和浏览器交互的数据。都是数据的拷贝哦,调用接口会发生复制行为。

    浏览器側

    浏览器側能够使用JavaScript来监听插件发送的message事件,也能够使用插件元素的postMessage发送消息给插件。

    基本上做以下几件事就可以:

    1. 实现处理消息的JS函数,其參数是MessageEvent。data成员为插件发过来的信息,能够当做JS对象来訪问。
    2. 监听插件的message事件
    3. 在合适的时候调用插件的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
    ", 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
    ", strCommand, len);
            OutputDebugStringA(szLog);
    
            if (len == 0)
            {
                OutputDebugString(_T("Tang_plugin, recv invalid command
    "));
                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
    ", szUserName, szConfId);
                OutputDebugStringA(szLog);
    
                if (szConfId && szUserName)
                {
                    sprintf_s(szLog, 256, "plugin got confId - %s, user - %s
    ", szConfId, szUserName);
                    OutputDebugStringA(szLog);
                    joinConf(szConfId, szUserName);
                }
                else
                {
                    OutputDebugString(_T("Invalid conference id or userName
    "));
                }
                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
    ", szUserId);
                    OutputDebugStringA(szLog);
                    viewVideo(szUserId, g_child_window);
                }
                else
                {
                    OutputDebugString(_T("Invalid viewVideo command without userId
    "));
                }
                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
    "));
            return &instance_interface;
        }
        else if (strcmp(interface_name, PPP_INPUT_EVENT_INTERFACE) == 0)
        {
            OutputDebugString(_T("PPP_GetInterface, input_interface
    "));
            return &input_interface;
        }
        else if (strcmp(interface_name, PPP_MESSAGING_INTERFACE) == 0)
        {
            OutputDebugString(_T("PPP_GetInterface, message_interface
    "));
            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" />&nbsp;&nbsp;User: 
    <input type="text" id="userName" />&nbsp;&nbsp;<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" />&nbsp;&nbsp;<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按钮之前是酱紫的:

    before

    点击Join按钮后是酱紫的:

    after


    其他參考文章:

  • 相关阅读:
    【JAVA Swing】自定义弹出的无边提醒框(可自动消失)
    java比较器Comparator的简单使用
    BoneCP的简单使用
    鸿蒙的js开发部模式18:鸿蒙的文件上传到python服务器端
    【知识点前情提要】鸿蒙小白入门指南!跟着张荣超老师学鸿蒙
    分布式流转开发常见报错FAQ
    Ability之间或者进程间数据传递之对象(Sequenceable序列化)
    【资源下载】安卓VS鸿蒙第三方件切换宝典 V1.0
    鸿蒙开源第三方组件 ——B站开源弹幕库引擎的迁移(上)
    鸿蒙的js开发部模式17:鸿蒙的系统能力的应用模块
  • 原文地址:https://www.cnblogs.com/cxchanpin/p/7074450.html
Copyright © 2020-2023  润新知