基于Cocoa And Web Kit框架的safari插件开发

一、     Safari 插件概述
Safari采用的是苹果自主开发的Webkit内核,包含WebCore排版引擎及JavaScriptCore解析引擎,均是从KDE的KHTML及KJS引擎衍生而来,它们都是自由软件,在GPL条约下授权,同时支持BSD系统的开发。在早期苹果为开发safari插件的开发人员提供了一套简单适用的Web Kit框架,但是该框架存在一个弊端,通过这种方式开发的插件能够通过safari访问存储在电脑中的数据,给用户的安全造成了巨大的威胁,所以在safari升级的5.1后就不支持该框架的插件,而是改用了比较流行的Netscape API框架,这种插件在运行时和safari是相对独立的,各自有自己的线程,所以就算是插件遇见问题挂了,safari还是能够正常运行的。插件可以编译为32位和64位插件,但是Safari在加载32位的插件前,需要做一些更改(右键->简介->以32位运行),尽管可以在Safari已安装的插件条目中找到所有插件(32和64bit),但是在页面加载时会直接跳过。另外插件的开发,调试工作都可以通过XCode来完成,但是在XCode下调试插件时,必须将插件编译成32位的,否则尽管插件能够被加载,但是代码中的断点却进不去。
二、     方法和步骤:
1.     打开XCode,选择File->New Project在弹出的对话框的左边选择Mac OS X下的Application Plug-in,然后在右边选择WebKit Plug-in,这样就能新建一个Safari插件工程了。
2.     在新建好的工程中会默认的生成一些文件,这些文件都是必须的,我们只能在上面进行增删改,不能将WebKitPluginView整个文件给删除掉,我们要做的工作就是把里面的函数填写完整就行。
3.     打开WebKitPluginView文件可以看到,其实Webkit Plug-in是一个NSView的子类,该文件默认生成了插件的已生存周期所需要的所有函数接口,而我们需要做的事情就是讲这些接口填满代码,完成需求。
(1)              + (NSView *)plugInViewWithArguments: (NSDictionary *)newArguments
主要功能: Theprincipal class of the plug-in bundle must implement this protocol. 个人理解这个函数需要做两件事:
a)     初始化一个NSView,为插件分配空间, NSView *pView = [[[self alloc] _initWithArguments:newArguments]autorelease];并返回这个NSView作为插件的主界面。
2.获取插件加载时页面传入的参数。比如说:加载插件的网页代码:要获取传入的宽和高就可以通过参数newArguments来获取。
b)      - (void)webPlugInInitialize
主要功能:顾名思义这个函数主要完成的工作也是初始化,但是这个主要工作是初始化内部成员变量,在程序的整个运行中只会被执行一次,也是第一个被执行的函数。
另外上一个函数中只是创建了一个NSView,没有任何东西显示在上面,在初始化完所有的成员变量后添加下面的代码初始化界面显示。
[NSBundleloadNibNamed: @"VxAudioPluginView" owner:self];
执行这段代码后,就会将事先设计好的界面(VxAudioPluginView.xib是xcode下界面设计文件)绑定到函数plugInViewWithArguments初始化的view中。
调用这段代码后,如果在代码中定义了函数-(void)awakeFromNib,程序接下来会执行它。
c)     其它关于webPlugInStart,webPlugInStop,webPlugInDestroy函数都看程序具体情况实现。
4.     实现绑定的界面文件中所有逻辑和功能,这点和开发一般的mac应用程序处理都一样。
三、     使用Qt界面库
1.     编辑Target中的项:
a)       Other LinkerFlags
-L/usr/local/Trolltech/Qt-4.7.3/lib -F/usr/local/Trolltech/Qt-4.7.3/lib -L/Qt_4.7.3/lib -L$(QTDIR)/lib -F$(QTDIR)/lib -L$(QTDIR)/lib -F$(QTDIR)/lib -F/Qt_4.7.3/lib -framework QtCore -framework QtGui -framework QtXml -framework QtNetwork
b)        Header Search Paths
/usr/local/Trolltech/Qt-4.7.3/lib/QtCore.framework/Versions/4/Headers /usr/local/Trolltech/Qt-4.7.3/include/QtCore /usr/local/Trolltech/Qt-4.7.3/lib/QtGui.framework/Versions/4/Headers /usr/local/Trolltech/Qt-4.7.3/include/QtGui /usr/local/Trolltech/Qt-4.7.3/lib/QtXml.framework/Versions/4/Headers /usr/local/Trolltech/Qt-4.7.3/include/QtXml /usr/local/Trolltech/Qt-4.7.3/include /usr/local/Trolltech/Qt-4.7.3/mkspecs/macx-xcode
c)        Framework Search Paths
$QTDIR/lib
d)        Library Search Paths
$QTDIR/lib
2.     由于Qt只是嵌入到插件中运行的,一个程序不可能存在两种消息循环机制,幸好Qt早考虑到了这点,提供了相应的宏使得Qt的消息机制遵从要求的主机制。在程序初始化的时候,创建QApplication之前添加以下代码:
QApplication::setAttribute(Qt::AA_DontUseNativeMenuBar);
QApplication::setAttribute(Qt::AA_MacPluginApplication);
3.     创建一个QApplication实例。查看Qt帮助文档可知,创建QApp需要两个参数,但这两个参数一般都不会使用到,因此我们可以这样创建:
int argc = 1;
new QApplication(argc, NULL);
4.     如何将QWidget转化为一个NSView?
在cocoa中,显示出来的是一个窗口(NSWindow),而窗口中的内容是由很多很多个视图(NSView)组成的。而在Qt中显示出来的东西却是由一个个的QWidget组成而来,这就需要将QWidget转换为NSView,然后加入到插件初始化时的NSView的subView序列中,才能够实现在插件中显示Qt生成的界面。
a)       定义用户转换的父窗口QMacNativeWidget。(直接调用show()函数什么都不会发生)
    QMacNativeWidget *nativeWidget = new QMacNativeWidget();
    nativeWidget->move(0, 0);
    nativeWidget->setPalette(QPalette(Qt::red));
    nativeWidget->setAutoFillBackground(true);
b)       将一个自定义的QWidget加入到QMacNativeWidget。
    QVBoxLayout *layout = new QVBoxLayout();
    QPushButton *pushButton = new QPushButton("button");
    pushButton->setAttribute(Qt::WA_LayoutUsesWidgetRect);
    layout->addWidget(pushButton);
    nativeWidget->setLayout(layout);
c)       将QMacNativeWidget转换为一个NSView,并添加到插件的NSView中。
NSView *nativeWidgetView = reinterpret_cast(nativeWidget->winId());
[PluginView addSubView: nativeWidgetView];
d)       最后调用show函数显示,否则就前功尽弃了。
nativeWidget->show();
pushButton->show();
四、      XCode调试插件的方法。
1.     添加执行脚本,将编译好的插件放到插件目录下:
使用xcode打开插件工程,在最上端的标题栏处打开Project->NewBulid Phase->New Run Script Bulid Phase,拷贝下面的脚本。

#clean up any previous products/symbolic links in the Internet Plug-Ins folder
if [ -a"${USER_LIBRARY_DIR}/Internet Plug-Ins/${FULL_PRODUCT_NAME}" ]; then
rm -Rf"${USER_LIBRARY_DIR}/Internet Plug-Ins/${FULL_PRODUCT_NAME}"
fi

# Depending onthe build configuration, either copy or link to the most recent product
if ["${CONFIGURATION}" == "Debug" ]; then
# if we'redebugging, add a symbolic link to the plug-in
ln -sf"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}" \
"${USER_LIBRARY_DIR}/InternetPlug-Ins/${FULL_PRODUCT_NAME}"
elif ["${CONFIGURATION}" == "Release" ]; then
# if we'recompiling for release, just copy the plugin to the Internet Plug-ins folder
cp -Rfv"${TARGET_BUILD_DIR}/${FULL_PRODUCT_NAME}" \
"${USER_LIBRARY_DIR}/InternetPlug-Ins/${FULL_PRODUCT_NAME}"
fi
2.     连接Safari.app到执行程序。
Project->New Custom Executable->Executable Path->Choose->Safari.app
3.     Build and Debug 程序后,就会启动safari,然后在safari中输入需要加载插件的网址运行即可。
五、      一些总结
1.     使用Xcode调试时,safari的版本不能过高,否则代码中的断点始终都是无效的。经探索Safari 5.0.3能够调试,Safari5.1以上的基本不行。
2.     对于程序中的连接库最好是改成@loader_path/../Frameworks,实在改不了的使用@executable_path/../Frameworks,但是这些库就必须要拷贝到/Applications/Safari.app/Contents/Frameworks目录下。
3.     一定要修改文件Info.plist。红框内的值将作为网页加载插件的唯一标识
基于Cocoa And Web Kit框架的safari插件开发_第1张图片

你可能感兴趣的:(Mac,OSX开发)