今天讲一下ANPInterface。

大概是为了弥补NPAPI在Android上的不足,Google在Android的浏览器上实现了ANPInterface这么一个东西。说白了这玩意就是一系列的操作接口(函数),提供了一些NPAPI没有的东西。插件可以在初始化的时候获取这些ANPXXXInterface,并在运行过程中使用。

关于这些接口的使用,大家可以看一看作为例子的BrowserPlugin是怎么做的,

main.cpp中,声明了一些ANPInterface的全局变量:

ANPAudioTrackInterfaceV0    gSoundI;
ANPBitmapInterfaceV0        gBitmapI;
ANPCanvasInterfaceV0        gCanvasI;
ANPEventInterfaceV0         gEventI;
ANPLogInterfaceV0           gLogI;
ANPPaintInterfaceV0         gPaintI;
ANPPathInterfaceV0          gPathI;
ANPSurfaceInterfaceV0       gSurfaceI;
ANPSystemInterfaceV0        gSystemI;
ANPTypefaceInterfaceV0      gTypefaceI;
ANPWindowInterfaceV0        gWindowI;

下面则是中NP_Initialize里面的一段:

static const struct {
        NPNVariable     v;
        uint32_t        size;
        ANPInterface*   i;
    } gPairs[] = {
        { kAudioTrackInterfaceV0_ANPGetValue,   sizeof(gSoundI),    &gSoundI },
        { kBitmapInterfaceV0_ANPGetValue,       sizeof(gBitmapI),   &gBitmapI },
        { kCanvasInterfaceV0_ANPGetValue,       sizeof(gCanvasI),   &gCanvasI },
        { kEventInterfaceV0_ANPGetValue,        sizeof(gEventI),    &gEventI },
        { kLogInterfaceV0_ANPGetValue,          sizeof(gLogI),      &gLogI },
        { kPaintInterfaceV0_ANPGetValue,        sizeof(gPaintI),    &gPaintI },
        { kPathInterfaceV0_ANPGetValue,         sizeof(gPathI),     &gPathI },
        { kSurfaceInterfaceV0_ANPGetValue,      sizeof(gSurfaceI),  &gSurfaceI },
        { kSystemInterfaceV0_ANPGetValue,       sizeof(gSystemI),   &gSystemI },
        { kTypefaceInterfaceV0_ANPGetValue,     sizeof(gTypefaceI), &gTypefaceI },
        { kWindowInterfaceV0_ANPGetValue,       sizeof(gWindowI),   &gWindowI },
    };
    for (size_t i = 0; i < ARRAY_COUNT(gPairs); i++) {
        gPairs[i].i->inSize = gPairs[i].size;
        NPError err = browser->getvalue(NULL, gPairs[i].v, gPairs[i].i);
        if (err) {
            return err;
        }
    }

该段的目的就是通过浏览器NPN接口里面的getvalue获取一系列ANPInterface。由于定义为了全局变量,所以这些接口可以在随时随地使用,就像这样:

gLogI.log(kDebug_ANPLogType, "------ %p DrawingModel is %d", instance, model);

 

 

下面就我所知道的情况说说这些接口都提供了哪些操作。
ANPAudioTrackInterface      这是一套音频接口,提供了播放音轨的功能
ANPBitmapInterface          只有一个函数getPixelPacking,依照给定的格式设置PixelPacking的参数值
ANPCanvasInterface          提供了一系列ANPCanvas绘图操作,其实就是把skia的Skcanvas相关接口作了一个包装
ANPEventInterface           提供了一个postEvent函数,插件可以用来向自己发送自定义的消息(ANPEvent)。
ANPLogInterface             提供了logcat的输出
ANPPaintInterface           包装了skia的SkPaint的相关接口,如果要用ANPCanvas画图,那就可能需要用这些接口来设置ANPPaint参数
ANPMatrixInterface          提供了ANPMatrix(SkMatrix)的一些操作接口,用ANPCanvas画图时可能会用到
ANPPathInterface            提供了ANPPath(SkPath)的一些操作接口,用ANPCanvas画图时可能会用到
ANPSurfaceInterface         提供了从SurfaceView中获取画布ANPBitmap的接口lock,以及提交绘图结果的接口unlock
ANPSystemInterface          getApplicationDataDirectory可以获取一个叫做PluginSharedDataDirectory的地址,具体我也没试过;2.2中新增了一个接口loadJavaClass,用于获取Java Class的实例,这个主要是用在加载过程中View的实例化。
ANPTypefaceInterface        这个我不是太清楚,似乎又是skia中一些功能的封装,大概和字体有关
ANPWindowInterface          一些窗口操作的接口,包括显示软键盘、全屏控制等等

 

 

具体定义可以看external/webkit/WebKit/android/plugins下的相关文件
使用方法可以参考development/samples/BrowserPlugin这个例子。

可以看出,其实ANPInterface提供的接口,其实现大多来自webkit以外的一些底层库。或许有人会问,这和直接连接这些库有什么区别?其实从结果上看,这两种方法都是殊途同归的,不过ANPInterface更多地体现为一种包装,就算底层库有了变动,只要ANPInterface不变,插件的代码就不需要修改。例如从Android 2.1到2.2,surfaceflinger有了较大的变化,但是ANPSurfaceInterface没有改变,因此插件也就不需要对这部分作什么修改。不过实际使用过程中,还是根据自己的需要去选择用ANPInterface还是直接连接外部库吧,毕竟ANPInterface提供的接口还是很有限的。