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中就需要导入相关的插件
Plug-in | Description |
---|---|
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,导致无法下载新的版本,但是日志没有任何显示,浪费很多时间