Equinox p2
Eclipsercp产品中通过配置Equinoxp2,从而实现新版本的检测,更新功能。
项目源码下载及文档说明:http://download.youkuaiyun.com/detail/luoww1/7693857
参考文章:
原文:http://javaarm.com/faces/display.xhtml?tid=3455&page=1
https://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application
https://wiki.eclipse.org/Equinox/p2/Adding_Self_Update_to_an_RCP_Application-3.5
http://www.vogella.com/tutorials/EclipseP2Update/article.html
运行环境
Eclipse4.3 kepler版本的Eclipse RCP IDE,可以从官网上下载
准备Eclipse RCP项目
- com.ybxiang.equinox.p2.example.email.application:这是我们的Eclipse RCP Application的核心,其中com.ybxiang...Application实现了org.eclipse.equinox.app.IApplication接口。
- com.ybxiang.equinox.p2.example.email.feature:这是一个feature项目,用于包含我们的应用程序所需的所有插件和features。
- com.ybxiang.equinox.p2.example.email.product:这事一个product项目,用于将我们的应用程序导出成产品。
1. 创建com.ybxiang.equinox.p2.example.email.application项目
打开菜单
设置项目名字和存放位置:
设置插件ID等信息:
我们期望我们的应用程序带有“Help”和“Window”菜单,因此我们选择“RCP MailTemplate”这个带有基本菜单(“File”和“Help”)的模板:
点击上面Finish按钮之后,打开plugin.xml文件,选中“Dependencies”标签页,然后按照下面的图示,点击“Add按钮”并添加4个插件:
· org.eclipse.equinox.p2.ui
· org.eclipse.equinox.p2.ui.sdk
· org.eclipse.equinox.p2.ui.sdk.scheduler
· org.eclipse.equinox.p2.transport.ecf
如果不选中该插件,就会导致导出程序在“联系软件站点”时出现下面的错误:
(参见:http://www.eclipse.org/forums/index.php/t/367402/)
!ENTRY org.eclipse.core.jobs 4 2 2014-04-10 20:31:59.117
|
最终所有依赖如下:
提示:
经过我们测试,实际还需要添加“org.eclipse.equinox.p2.touchpoint.natives”这个插件,否则后面更新插件时,会出错;我们在这里不添加该插件,后面遇到错误后,会描述如何修复。如果读者不期望在后面的测试章节中出现该错误,请在上图中将“org.eclipse.equinox.p2.touchpoint.natives”插件添加进来。 |
l 状态栏和进度指示条
为了能够清楚地看到软件升级进度,我们需要修改ApplicationWorkbenchWindowAdvisor.java这个文件,使之显示状态栏和进度指示条。
public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { |
l Window中添加Preferences子菜单
private IWorkbenchAction preferencesAction; protected void makeActions(final IWorkbenchWindow window) { …… preferencesAction = ActionFactory.PREFERENCES.create(window); register(preferencesAction); } protected void fillMenuBar(IMenuManager menuBar) { …… MenuManager windowMenu = new MenuManager("&Window", IWorkbenchActionConstants.M_WINDOW); menuBar.add(windowMenu); windowMenu.add(preferencesAction); } |
l 运行测试
我们Email的程序启动只有之后,请遵照下面的步骤,查看相关功能:
2. 创建com.ybxiang.equinox.p2.example.email.feature
创建一个 feature项目,用来包括我们的”整个Email应用程序“所需要的所有插件和其它Feature
选择”Feature Project“菜单:
输入Feature相关信息:
让该feature包含我们刚刚创建的Email应用程序插件:
注意:
上图中没有必要勾中“com.ybxiang.equinox.p2.example.email.application”所依赖的那些插件(比如 org.eclipse.equinox.p2.ui,org.eclipse.equinox.p2.ui.sdk,org.eclipse.equinox.p2.ui.sdk.scheduler和org.eclipse.equinox.p2.transport.ecf),我们在后面会点击Feature插件的“Compute”按钮来计算出间接依赖的插件! |
我们的应用程序当然应该包含 org.eclipse.rcp 这个大feature。如下图添加该feature:
最后,进入“Dependencies”标签页,点击“Compute按钮”,这样IDE就会计算并更新“com.ybxiang.equinox.p2.example.email.feature”所需要的所有插件:
3. 创建com.ybxiang.equinox.p2.example.email.product
创建项目
选择参考项目(我们不选择任何项目):
l 创建 productconfiguration文件:
选择参考项目(我们不选择任何项目):
输入product configuration文件的相关信息:
l 修改版本信息,定义product
注意:上图中,需要选中“Features”这个选择按钮!
添加该product所依赖的features:
注意:上图中,只需要添加“com.ybxiang.equinox.p2.example.email.feature”就可以了!该feature已经包含了该应用程序所需要的所有其它插件和features。
l 创建p2.inf
注意:p2.inf这个文件必须和 xxx.product文件位于相同目录之下,否则,导出产品的菜单“Window” >"Preferences" > "Install/Update"节点对应的页面中,就不会包含我们在p2.inf中所设置的软件站点(http${#58}//127.0.0.1:8080/repository):
正确的效果应该是这样:
l 运行product测试
打开“windows.product”文件,点击其中的“Launch an EclipseApplication”链接,我们会看到出错:
这是由于IDE运行 “windows.product”时,会为之创建一个runtime,而该runtime没有包含所有的所有插件所致,这应该是IDE的一个小bug。
该问题的修正办法如下:
左边选择“windows.product”,右边选中“Plug-ins”,然后点击“Add RequiredPlug-ins”按钮:
我们可以看到上图是“64 out of 620selected”,而下图是 “113 out of 620 selected”:
点击上图的Apply按钮之后,再点击上图中的“Debug”按钮,重新运行“windows.product”就不会出错了!
注意:
请总是点击工具条上的 "Debugas..."或"Run as..."下拉框,然后选择我们的产品,本文为“windows.product”,运行该产品!不要点击“windows.product”文件中的“Launch an EclipseApplication”链接来运行该产品,因为这样做的话,IDE会重建“windows.product”的runtime配置,也就是说覆盖掉我们在上面通过点击"Add RequiredPlug-ins"得到的配置!操作如下:
软件升级测试
1. 导出1.0.0版本的产品
点击下图中的“Eclipse Productexport wizrard”链接将我们的第一版产品导出:
设置导出配置:
导出结果:
运行 export-v1.0.0 下的 eclipse.exe文件,效果如下:
2. 修改产品版本为2.0.0
windows.product文件中,有2个地方需要修改:
针对项目com.ybxiang.equinox.p2.example.email.application中功能或显示进行修改,用于区分不同版本的功能。
3. 导出2.0.0版的产品
导出方法和上面一样,注意导出目录名字修改为 export-v2.0.0
4. 部署export-v2.0.0\repository
将C:\Users\yingbinx\Desktop\tmp\test\export-v2.0.0\repository 这个目录拷贝到 web 容器(本文使用tomcat)的web部署目录之下,然后启动web容器:
5. 更新export-v1.0.0/eclipse.exe
启动export-v1.0.0/eclipse.exe,然后点击菜单“Help” >"Check for Updates"子菜单:
我们可以看到我们的导出产品正在联系软件站点:
找到了更新版本(2.0.0)的程序:
接受许可证:
列举出将要安装的产品:
上图中,点击Next按钮之后,若出现如下图的错误:
解决方法:
打开com.ybxiang.equinox.p2.example.email.application/plugin.xml,在 Dependencies标签页中,添加“org.eclipse.equinox.p2.touchpoint.natives”插件。在com.ybxiang.equinox.p2.example.email.feature,点击feature.xml,进入“Dependencies”标签页,点击“Compute按钮”,这样IDE就会计算并更新“com.ybxiang.equinox.p2.example.email.feature”所需要的所有插件。然后重新打包产品1.0.0,2.0.0,然后在继续执行更新操作。
更新完毕后会提示你重新启动:
查看本产品所安装的插件/features:
可以看到2.0.0版本的产品已经安装好了:
也可以看到版本2.0.0中新添加的功能,或显示。
最后,我们可以看到 export-v1.0.0\eclipse\plugins 目录下已经有新版本的插件了:
设置产品启动时自动更新
打开产品的菜单”Window“ >"Preferences",选中节点 "Install/Update"> "Automatic Updates",然后在右侧按需设置自动更新既可。如下图:
错误总汇:
Eclipse 4.3中有项目设置过Bundle jre forthis environment with the product.
存在一个Bug,就是即使你去掉了对Bundle JRE forthis enviroment with the product的勾选,打包时照样会生成jre目录
这样会导致更新出错。
解决方法:
1、 重新下载Eclipse4.3版本,永远都不要勾选Bundle JRE forthis enviroment with the product。
2、 在导出的产品项目中,若要执行更新,就先删除jre文件夹,删除jre后会使用系统中的运行环境,在执行更新的时候会又会创建jre(主要是导出产品的时候在repository中记录了对jre的更新)
编程实现产品启动时软件更新检
根据 http://www.vogella.com/tutorials/EclipseP2Update/article.html#tutorial_updatelocation 一文的描述,我们可以在com.ybxiang.equinox.p2.example.email.application插件中,添加UpdateHandler.java,这样产品启动的时候,就会启动软件更新检查。
package org.jtang.synergy.handler; import java.net.URI; import java.net.URISyntaxException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.core.runtime.jobs.IJobChangeEvent; import org.eclipse.core.runtime.jobs.Job; import org.eclipse.core.runtime.jobs.JobChangeAdapter; import org.eclipse.e4.core.di.annotations.Execute; import org.eclipse.e4.ui.di.UISynchronize; import org.eclipse.e4.ui.workbench.IWorkbench; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.operations.ProvisioningJob; import org.eclipse.equinox.p2.operations.ProvisioningSession; import org.eclipse.equinox.p2.operations.Update; import org.eclipse.equinox.p2.operations.UpdateOperation; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.swt.widgets.Shell; /** * 用于自动更新 * @author lww * */ public class UpdateHandler { private static final String REPOSITORY_LOC = System.getProperty("UpdateHandler.Repo", "file://home/vogella/repository"); @Execute public void execute(final IProvisioningAgent agent, final Shell parent, final UISynchronize sync, final IWorkbench workbench) { Job j = new Job("Update Job") { private boolean doInstall = false; @Override protected IStatus run(final IProgressMonitor monitor) { /* 1. Prepare update plumbing */ final ProvisioningSession session = new ProvisioningSession(agent); final UpdateOperation operation = new UpdateOperation(session); // create uri URI uri = null; try { uri = new URI(REPOSITORY_LOC); } catch (final URISyntaxException e) { sync.syncExec(new Runnable() { @Override public void run() { MessageDialog .openError(parent, "URI invalid", e.getMessage()); } }); return Status.CANCEL_STATUS; } // set location of artifact and metadata repo operation.getProvisioningContext().setArtifactRepositories(new URI[] { uri }); operation.getProvisioningContext().setMetadataRepositories(new URI[] { uri }); /* 2. check for updates */ // run update checks causing I/O final IStatus status = operation.resolveModal(monitor); // failed to find updates (inform user and exit) if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) { sync.syncExec(new Runnable() { @Override public void run() { MessageDialog .openWarning(parent, "No update", "No updates for the current installation have been found"); } }); return Status.CANCEL_STATUS; } /* 3. Ask if updates should be installed and run installation */ // found updates, ask user if to install? if (status.isOK() && status.getSeverity() != IStatus.ERROR) { sync.syncExec(new Runnable() { @Override public void run() { String updates = ""; Update[] possibleUpdates = operation .getPossibleUpdates(); for (Update update : possibleUpdates) { updates += update + "\n"; } doInstall = MessageDialog.openQuestion(parent, "Really install updates?", updates); } }); } // start installation if (doInstall) { final ProvisioningJob provisioningJob = operation .getProvisioningJob(monitor); // updates cannot run from within Eclipse IDE!!! if (provisioningJob == null) { System.err .println("Running update from within Eclipse IDE? This won't work!!!"); throw new NullPointerException(); } // register a job change listener to track // installation progress and notify user upon success provisioningJob .addJobChangeListener(new JobChangeAdapter() { @Override public void done(IJobChangeEvent event) { if (event.getResult().isOK()) { sync.syncExec(new Runnable() {
@Override public void run() { boolean restart = MessageDialog .openQuestion(parent, "Updates installed, restart?", "Updates have been installed successfully, do you want to restart?"); if (restart) { workbench.restart(); } } }); } super.done(event); } }); provisioningJob.schedule(); } return Status.OK_STATUS; } }; j.schedule(); } } |
需要添加依赖插件(com.ybxiang.equinox.p2.example.email.application)
Plugin.xml中添加
在com.ybxiang.equinox.p2.example.email.feature项目 feature.xml中添加org.eclipse.equinox.p2.core.feature,并点击Compute按钮,把com.ybxiang.equinox.p2.example.email.application中新添加的插件添加进来。
把版本1.0.0的产品启动,就会有提示