eclipse rcp 需要增加自动update功能,希望使用Equinox P2的api来做相应的自动启动更新,不需要用户的干预.
参考:https://wiki.eclipse.org/Equinox/p2/Adding_Self-Update_to_an_RCP_Application
查看官方文档,下载git代码,就是跑不通.
偶尔发现一片文章:http://javaarm.com/faces/display.xhtml?tid=3455&page=1
讲的非常详细,一步一步下来,基本上实现了菜单更新.
下面需要实现无干预的更新,
参考:http://www.vogella.com/tutorials/EclipseP2Update/article.html#tutorial_updatelocation
最终实现代码如下:
ApplicationWorkbenchWindowAdvisor:
package com.xsej.office; import java.lang.reflect.InvocationTargetException; import org.eclipse.core.runtime.IProgressMonitor; import org.eclipse.core.runtime.IStatus; import org.eclipse.core.runtime.Status; import org.eclipse.equinox.internal.p2.core.helpers.LogHelper; import org.eclipse.equinox.internal.p2.core.helpers.ServiceHelper; import org.eclipse.equinox.p2.core.IProvisioningAgent; import org.eclipse.equinox.p2.operations.UpdateOperation; import org.eclipse.jface.dialogs.MessageDialog; import org.eclipse.jface.dialogs.ProgressMonitorDialog; import org.eclipse.jface.operation.IRunnableWithProgress; import org.eclipse.jface.preference.IPreferenceStore; import org.eclipse.swt.graphics.Point; import org.eclipse.swt.widgets.Display; import org.eclipse.ui.PlatformUI; import org.eclipse.ui.application.ActionBarAdvisor; import org.eclipse.ui.application.IActionBarConfigurer; import org.eclipse.ui.application.IWorkbenchWindowConfigurer; import org.eclipse.ui.application.WorkbenchWindowAdvisor; import com.xsej.office.utils.P2Util; public class ApplicationWorkbenchWindowAdvisor extends WorkbenchWindowAdvisor { private static final String JUSTUPDATED = "justUpdated"; public ApplicationWorkbenchWindowAdvisor( IWorkbenchWindowConfigurer configurer) { super(configurer); } public ActionBarAdvisor createActionBarAdvisor( IActionBarConfigurer configurer) { return new ApplicationActionBarAdvisor(configurer); } public void preWindowOpen() { IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); int screenWidth = Display.getCurrent().getBounds().width; int screenHeight = Display.getCurrent().getBounds().height; configurer.setInitialSize(new Point(screenWidth, screenHeight)); configurer.setShowCoolBar(true); configurer.setShowStatusLine(true); configurer.setShowProgressIndicator(true); configurer.setTitle("example"); } public void postWindowOpen() { IWorkbenchWindowConfigurer configurer = getWindowConfigurer(); configurer.getWindow().getShell().setMaximized(true); final IProvisioningAgent agent = (IProvisioningAgent) ServiceHelper .getService(Activator.bundleContext, IProvisioningAgent.SERVICE_NAME); if (agent == null) { LogHelper .log(new Status(IStatus.ERROR, Activator.PLUGIN_ID, "No provisioning agent found. This application is not set up for updates.")); } // XXX if we're restarting after updating, don't check again. final IPreferenceStore prefStore = Activator.getDefault() .getPreferenceStore(); if (prefStore.getBoolean(JUSTUPDATED)) { prefStore.setValue(JUSTUPDATED, false); return; } // XXX check for updates before starting up. // If an update is performed, restart. Otherwise log // the status. IRunnableWithProgress runnable = new IRunnableWithProgress() { public void run(IProgressMonitor monitor) throws InvocationTargetException, InterruptedException { IStatus updateStatus = P2Util.checkForUpdates(agent, monitor); if (updateStatus.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) { // PlatformUI.getWorkbench().getDisplay() // .asyncExec(new Runnable() { // public void run() { // MessageDialog.openInformation(null, "提示", // "已经是最新版本"); // } // }); } else if (updateStatus.getSeverity() != IStatus.ERROR) { prefStore.setValue(JUSTUPDATED, true); PlatformUI.getWorkbench().getDisplay() .asyncExec(new Runnable() { public void run() { MessageDialog.openInformation(null, "提示", "更新完成,现在重启"); PlatformUI.getWorkbench().restart(); } }); // PlatformUI.getWorkbench().restart(); } else { LogHelper.log(updateStatus); } } }; try { new ProgressMonitorDialog(null).run(true, true, runnable); } catch (InvocationTargetException e) { e.printStackTrace(); LogUtil.log(this.getClass(),e.toString() ); } catch (InterruptedException e) { e.printStackTrace(); LogUtil.log(this.getClass(),e.toString() ); } catch (Exception e) { e.printStackTrace(); LogUtil.log(this.getClass(),e.toString() ); } } public boolean preWindowShellClose() { return true; } }
P2Util:
package com.xsej.office.utils; 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.OperationCanceledException; import org.eclipse.core.runtime.SubMonitor; 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.UpdateOperation; public class P2Util { private static final String REPOSITORY_LOC = System.getProperty( "P2Util.Repo", "http://127.0.0.1:8080/repository"); // XXX Check for updates to this application and return a status. public static IStatus checkForUpdates(IProvisioningAgent agent, IProgressMonitor monitor) throws OperationCanceledException { ProvisioningSession session = new ProvisioningSession(agent); // the default update operation looks for updates to the currently // running profile, using the default profile root marker. To change // which installable units are being updated, use the more detailed // constructors. UpdateOperation operation = new UpdateOperation(session); configureUpdate(operation); SubMonitor sub = SubMonitor.convert(monitor, "正在检查更新...", 200); IStatus status = operation.resolveModal(sub.newChild(100)); if (status.getCode() == UpdateOperation.STATUS_NOTHING_TO_UPDATE) { return status; } if (status.getSeverity() == IStatus.CANCEL) throw new OperationCanceledException(); if (status.getSeverity() != IStatus.ERROR) { // More complex status handling might include showing the user what // updates // are available if there are multiples, differentiating patches vs. // updates, etc. // In this example, we simply update as suggested by the operation. ProvisioningJob job = operation.getProvisioningJob(null); status = job.runModal(sub.newChild(100)); if (status.getSeverity() == IStatus.CANCEL) throw new OperationCanceledException(); } return status; } private static UpdateOperation configureUpdate( final UpdateOperation operation) { // create uri and check for validity URI uri = null; try { uri = new URI(REPOSITORY_LOC); } catch (final URISyntaxException e) { return null; } LogUtil.log("更新地址:"+uri.toString() ); // set location of artifact and metadata repo operation.getProvisioningContext().setArtifactRepositories( new URI[] { uri }); operation.getProvisioningContext().setMetadataRepositories( new URI[] { uri }); return operation; } }
总结:
1.构建整理,原来只是一个plugin工程,但是最后演变成三个工程,原来的plugin工程,feature工程,product工程.
主要p2需要针对feature进行update.
2.自动更新需要使用equinox p2的api进行无干预更新,那么在plugin中就需要导入相关的插件
org.eclipse.equinox.p2.core |
Core p2 functionality |
org.eclipse.equinox.p2.engine |
The engine carries out the provisioning operation. |
org.eclipse.equinox.p2.operations |
Layer over the core and engine API to describe updates as an atomic install. |
org.eclipse.equinox.p2.metadata.repository |
Contains the definition of p2 repositories. |
需要添加另外更新需要使用的插件;
org.eclipse.equinox.p2.touchpoint.natives
org.eclipse.equinox.p2.transport.ecf
在feature中包含整个p2的featrue包
org.eclipse.equinox.p2.core.feature |
Feature containing the p2 bundles. |
开发过程因为没有加入org.eclipse.equinox.p2.metadata.repository,导致无法下载新的版本,但是日志没有任何显示,浪费很多时间