Embed Firefox browser in Java Swing - java

I am wondering if it is possible to embed Firefox browser as a component in a Java Swing based application.
I have done a bit of research from the Internet, but I could not find an answer. Some people suggest to use other browser component available in Java. I do not think that is preferable, as the rendering engine would be different to Firefox.
Any idea? Many thanks.

Absolutely I have done it before please check out the Mozilla Embedding for Java
Here is some sample code
import java.awt.Color;
import java.awt.Component;
import java.awt.Container;
import java.awt.FlowLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.io.FileNotFoundException;
import java.io.File;
import javax.swing.*;
import org.mozilla.xpcom.*;
import org.mozilla.interfaces.*;
/*
Websites ref
http://groups.google.com/group/mozilla.dev.tech.java/browse_thread/thread/898ba6751d0c57f7
http://skrul.com/blog/code/
http://wirestorm.net/blog/?cat=9
*/
public class BrowserTest implements nsIWebProgressListener,nsIWeakReference, nsIInterfaceRequestor, nsIWebBrowserChrome, nsISHistoryListener{
static {
try {
System.loadLibrary("NativeWindow");
} catch (UnsatisfiedLinkError e) {
System.err.println("can't find your library");
}
}
private static final String frameTitle="GRE Embedded";
public static void main(String[] args) {
BrowserConroller controler=new BrowserConroller();
controler.run();
new BrowserTest().start();
}
public void start(){
JFrame f = new JFrame( frameTitle );
f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
f.setSize(400, 150);
Container content = f.getContentPane();
content.setBackground(Color.white);
content.setLayout(new FlowLayout());
content.add(new JLabel("Initializing ... "));
f.setVisible(true);
File grePath = null;
LocationProvider locProvider;
Mozilla mozilla = Mozilla.getInstance();
GREVersionRange[] range = new GREVersionRange[1];
range[0] = new GREVersionRange("1.8.0", true, "1.9", false);
try {
grePath = Mozilla.getGREPathWithProperties(range, null);
mozilla.initialize(grePath);
locProvider = new LocationProvider(grePath);
mozilla.initEmbedding(grePath, grePath, locProvider);
}
catch (FileNotFoundException e) {
System.out.println("Error: FileNotFoundException");
}
catch (XPCOMException e) {
System.out.println("Error: XPCOMException");
}
//---------- END GRE INITIALIZATION------------
nsIServiceManager serviceManager = mozilla.getServiceManager();
nsIAppStartup appStartup = (nsIAppStartup)serviceManager.getServiceByContractID("#mozilla.org/toolkit/app-startup;1", nsIAppStartup.NS_IAPPSTARTUP_IID);
nsIWindowCreator windowCreator = (nsIWindowCreator)appStartup.queryInterface(nsIWindowCreator.NS_IWINDOWCREATOR_IID);
nsIWindowWatcher windowWatcher =(nsIWindowWatcher)serviceManager.getServiceByContractID("#mozilla.org/embedcomp/window-watcher;1",nsIWindowWatcher.NS_IWINDOWWATCHER_IID);
windowWatcher.setWindowCreator(windowCreator);
nsIDOMWindow win = windowWatcher.openWindow(null, "http://google.com", "MAIN_WIN","chrome,resizable,centerscreen", null);
windowWatcher.setActiveWindow( win );
nsIComponentManager componentManager = mozilla.getComponentManager();
String NS_IWEBBROWSER_CID = "F1EAC761-87E9-11d3-AF80-00A024FFC08C"; //$NON-NLS-1$
nsIWebBrowser webBrowser = (nsIWebBrowser) componentManager.createInstance(NS_IWEBBROWSER_CID, null, nsIWebBrowser.NS_IWEBBROWSER_IID);
webBrowser.setContainerWindow(this);
webBrowser.addWebBrowserListener(this, nsIWebProgressListener.NS_IWEBPROGRESSLISTENER_IID);
// nsIWebNavigation webNavigation=(nsIWebNavigation)webBrowser.queryInterface(nsIWebNavigation.NS_IWEBNAVIGATION_IID);
// webNavigation.loadURI("http://www.zdnet.com", nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
//
nsIBaseWindow baseWindow = (nsIBaseWindow) webBrowser.queryInterface(nsIBaseWindow.NS_IBASEWINDOW_IID);
long handle=FindWindow.getHWND( frameTitle );
baseWindow.initWindow(handle, 0, 0, 0,350,350);
baseWindow.create();
baseWindow.setVisibility(true);
//
// nsIDOMWindow domWin=webBrowser.getContentDOMWindow();
// nsIDOMEventTarget domEventTarget= (nsIDOMEventTarget)domWin.queryInterface(nsIDOMEventTarget.NS_IDOMEVENTTARGET_IID);
// domEventTarget.addEventListener("click", new EventListener(), false);
//
//Hide JFrame after it have been initialized
f.setVisible(true);
//
// nsIWebNavigation webNavigation=(nsIWebNavigation)webBrowser.queryInterface(nsIWebNavigation.NS_IWEBNAVIGATION_IID);
// webNavigation.loadURI("http://www.zdnet.com", nsIWebNavigation.LOAD_FLAGS_NONE, null, null, null);
//
appStartup.run();
System.out.println("try termEmbedding");
try {
System.out.println("mozilla.termEmbedding(); START");
mozilla.termEmbedding();
System.out.println("mozilla.termEmbedding(); FINISHED");
}
catch (XPCOMException e) {
System.out.println("Fehler: XPCOMException");
}
System.out.println("finished termEmbedding");
System.out.println("All done");
}
public void onLocationChange(nsIWebProgress webProgress, nsIRequest request, nsIURI location) {
c("onLocationChange");
}
public void onProgressChange(nsIWebProgress webProgress, nsIRequest request, int curSelfProgress, int maxSelfProgress, int curTotalProgress, int maxTotalProgress) {
c("onProgressChange");
}
public void onSecurityChange(nsIWebProgress webProgress, nsIRequest request, long state) {
c("onSecurityChange");
}
public void onStateChange(nsIWebProgress webProgress, nsIRequest request, long stateFlags, long status) {
c("onStateChange");
}
public void onStatusChange(nsIWebProgress webProgress, nsIRequest request, long status, String message) {
c("onStatusChange");
}
public nsISupports queryInterface(String uuid) {
c("queryInterface");
return null;
}
public nsISupports queryReferent(String uuid) {
c("queryReferent");
return null;
}
public nsISupports getInterface(String uuid) {
c("getInterface");
return null;
}
private void c(Object o){
System.out.println(o);
}
public void destroyBrowserWindow() {
c("destroyBrowserWindow");
}
public void exitModalEventLoop(long status) {
c("exitModalEventLoop");
}
public long getChromeFlags() {
c("getChromeFlags");
return 0;
}
public nsIWebBrowser getWebBrowser() {
c("getWebBrowser");
return null;
}
public boolean isWindowModal() {
c("isWindowModal");
return false;
}
public void setChromeFlags(long chromeFlags) {
c("setChromeFlags");
}
public void setStatus(long statusType, String status) {
c("setStatus");
}
public void setWebBrowser(nsIWebBrowser webBrowser) {
c("setWebBrowser");
}
public void showAsModal() {
c("showAsModal");
}
public void sizeBrowserTo(int acx, int acy) {
c("sizeBrowserTo");
}
public boolean onHistoryGoBack(nsIURI backURI) {
c("onHistoryGoBack");
return false;
}
public boolean onHistoryGoForward(nsIURI forwardURI) {
c("onHistoryGoForward");
return false;
}
public boolean onHistoryGotoIndex(int index, nsIURI gotoURI) {
c(" onHistoryGotoIndex");
return false;
}
public void onHistoryNewEntry(nsIURI newURI) {
c(" onHistoryNewEntry");
}
public boolean onHistoryPurge(int numEntries) {
c(" onHistoryPurge");
return false;
}
public boolean onHistoryReload(nsIURI reloadURI, long reloadFlags) {
c(" onHistoryReload");
return false;
}
} //public class JavaXPCOM_test1[/code]

As answered here (Best Java/Swing browser component?) - and from my own testing - djproject seems to be the best.
It has last been updated March 2009 and some demo links are broken.. so the project seems not to be too active right now.. Still: When I needed it in 2010 it was awesome.

A quick Google search returns a product called JxBrowser that does this.
However, I would question whether you really need a full blown browser component like Firefox in your application. What do you need it for in your application?

How about embedding your GUI inside the browser instead, with an applet, GWT or another rich client approach?

Not directly. You could port your UI (or at least part of it) to SWT and then use the Browser component (see this FAQ item).
If you can't port your UI to SWT, then you can embed your Swing UI in SWT (SWT Shell == Swing JFrame). But there will be some pain ahead.
Update: Firefox is no longer supported by SWT. Currently supported is the system's default browser or WebKit (see https://github.com/eclipse/eclipse.platform.swt/search?q=BrowserFactory&unscoped_q=BrowserFactory).

Related

How can I call a method in a JavaFX Application's preloader instance from the main Application's init() method

In a JavaFX application's init() method I am doing some checks, one of them is a check to see if it can connect to a web address based using Http response codes. This app also has a preloader that runs while these checks are happening.
Depending on the response code, I want it to display an alert window during the preloader application's lifecycle
I am not sure if this is possible using the current javafx preloader class, but is there any workarround that could achieve this?
below is an SSCCE of what I would want
The Application
public class MainApplicationLauncher extends Application implements Initializable{
...
public void init() throws Exception {
for (int i = 1; i <= COUNT_LIMIT; i++) {
double progress =(double) i/10;
System.out.println("progress: " + progress);
notifyPreloader(new ProgressNotification(progress));
Thread.sleep(500);
}
try {
URL url = new URL("https://example.com");
HttpURLConnection connection = (HttpURLConnection)url.openConnection();
connection.setRequestMethod("GET");
connection.connect();
int code = connection.getResponseCode();
System.out.println("Response code of the object is "+code);
if (code==200) {
System.out.println("Connected to the internet!");
}else if (code==503){
//call the handleConnectionWarning() in preloader
System.out.println("server down !");
}
} catch (UnknownHostException e) {
//call the handleConnectionWarning() in preloader
System.out.println("cannot connect to the internet!");
}
public static void main(String[] args) {
System.setProperty("javafx.preloader", MainPreloader.class.getCanonicalName());
Application.launch(MainApplicationLauncher.class, args);
}
}
The preloader
public class MyPreloader extends Preloader{
...
//Method that should be called from application method
public void handleConnectionWarning() {
Alert alert = new Alert(AlertType.WARNING);
alert.setTitle("Server is Offline");
alert.setHeaderText("Cannot connect to service");
alert.setContentText("Please check your connection");
alert.showAndWait();
}
}
Are there any ways to do this?
Preloader
If you want to continue using Preloader for your splash screen, then you can call the desired method via a notification. Create your own notification class:
// You can modify this class to carry information to the Preloader, such
// as a message indicating what kind of failure occurred.
public class ConnectionFailedNotification implements Preloader.PreloaderNotification {}
Send it to your Preloader:
notifyPreloader(new ConnectionFailedNotification());
And handle it in said Preloader:
#Override
public void handleApplicationNotification(PreloaderNotification info) {
if (info instanceof ConnectionFailedNotification) {
handleConnectionWarning();
}
// ...
}
No Preloader
The Preloader class makes more sense when you're deploying your application via Java Web Start (i.e., to web browsers), where the code has to be downloaded before it can be used. But Java Web Start is no longer supported (though I think there may be a third-party maintaining something at least similar). Given your application is likely targeted for a simple desktop deployment, using Preloader can make things unnecessarily complicated. Instead consider simply updating the primary stage's content after initialization.
Move your init() stuff into a Task implementation:
import java.io.IOException;
import javafx.concurrent.Task;
public class InitTask extends Task<Void> {
private static final int COUNT_LIMIT = 10;
private final boolean shouldSucceed;
public InitTask(boolean shouldSucceed) {
this.shouldSucceed = shouldSucceed;
}
#Override
protected Void call() throws Exception {
for (int i = 1; i <= COUNT_LIMIT; i++) {
updateProgress(i, COUNT_LIMIT);
Thread.sleep(500);
}
// could use a Boolean return type for this, but your real code seems
// more complicated than a simple "yes" / "no" response. If you do
// change the implementation to use a return value, note that you would
// then need to check that return value in the 'onSucceeded' handler
if (!shouldSucceed) {
throw new IOException("service unavailable"); // failure
}
return null; // success
}
}
And then launch that task on a background thread:
import javafx.application.Application;
import javafx.application.Platform;
import javafx.scene.Scene;
import javafx.scene.control.Alert;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.Alert.AlertType;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;;
public class App extends Application {
#Override
public void start(Stage primaryStage) throws Exception {
var task = new InitTask(false); // change to 'true' to simulate success
task.setOnSucceeded(e -> primaryStage.getScene().setRoot(createMainScreen()));
task.setOnFailed(e -> {
var alert = new Alert(AlertType.WARNING);
alert.initOwner(primaryStage);
alert.setTitle("Server Offline");
alert.setHeaderText("Cannot connect to service");
alert.setContentText("Please check your connection");
alert.showAndWait();
Platform.exit();
});
// Also see the java.util.concurrent.Executor framework
var thread = new Thread(task, "init-thread");
thread.setDaemon(true);
thread.start();
var scene = new Scene(createSplashScreen(task), 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private StackPane createSplashScreen(InitTask task) {
var bar = new ProgressBar();
bar.progressProperty().bind(task.progressProperty());
return new StackPane(bar);
}
private StackPane createMainScreen() {
return new StackPane(new Label("Hello, World!"));
}
}
Side Notes
Your Application subclass should not implement Initializable. That subclass represents the entire application and should never be used as an FXML controller.

How to dynamically configure log directory (every request) in java util logging with helidon

I want to configure separate log directory for every request. Is this possible with helidon?
The oracle helidon JUL examples are located in github. Building off of those examples you would have to create a custom Handler to read the request from the HelidonMdc:
import io.helidon.logging.jul;
import io.helidon.logging.common;
import java.util.logging.*;
public class RequestFileHandler extends Handler {
public RequestFileHandler() {
super.setFormatter(new HelidonFormatter());
}
#Override
public synchronized void publish(LogRecord r) {
if (isLoggable(r)) {
try {
FileHandler h = new FileHandler(fileName(r), Integer.MAX_VALUE, 1, true);
try {
h.setLevel(getLevel());
h.setEncoding(getEncoding());
h.setFilter(null);
h.setFormatter(getFormatter());
h.setErrorManager(getErrorManager());
h.publish(r);
} finally {
h.close();
}
} catch (IOException | SecurityException jm) {
this.reportError(null, jm, ErrorManager.WRITE_FAILURE);
}
}
}
#Override
public void flush() {
}
#Override
public void close() {
super.setLevel(Level.OFF);
}
private String fileName(LogRecord r) {
Optional<String> o = HelidonMdc.get("name");
return o.isPresent() ? o.get() +".log" : "unknown.log";
}}
Like the example code this code is assuming that you have set the value of 'name' to the request id. You would then have to install this handler on your application logger.

Flickering Annotations in WorldWind Java

I'm trying to implement my own clutter filter in NASA Worldwind for Java and its causing a weird problem -- the clutter filter isn't doing much yet, but I will use it to move things around when I get passed the "flickering" issue. Whenever the mouse is moved the GlobeAnnotation renderables are flickering. When I have the clutter filter set to null, the flickering does not seem to occur.
Here is a GIF that shows what I mean: https://media.giphy.com/media/xT9IgFiZwYZ3VJHQU8/giphy.gif
I've cloned the NASA worldwind code from here: https://github.com/NASAWorldWind/WorldWindJava. I've made a couple of changes to make things work for my eventual filter. One note is that I want the GlobeAnnotations to appear as Always On Top of everything else.
How can I make the GlobeAnnotations not fight with each other and flicker, but still appear on top of everything else -- while having the Clutter Filter turned on?
Note that the following code is just an example I put together to show the issue that I'm seeing in my "real" application. I want the GlobeAnnotations to always be on top of everything else -- but not flickering and fighting with each other.
Here is my test driver:
package gov.nasa.worldwindx.examples;
import java.awt.Color;
import gov.nasa.worldwind.geom.LatLon;
import gov.nasa.worldwind.geom.Position;
import gov.nasa.worldwind.layers.AnnotationLayer;
import gov.nasa.worldwind.layers.RenderableLayer;
import gov.nasa.worldwind.render.GlobeAnnotation;
import gov.nasa.worldwind.render.Material;
import gov.nasa.worldwind.render.airspaces.CappedCylinder;
public class FlashyAnnotations extends ApplicationTemplate {
#SuppressWarnings("unchecked")
private static class AppFrame extends ApplicationTemplate.AppFrame {
private AnnotationLayer layer;
public AppFrame() {
this.getWwd().getSceneController().setClutterFilter(new SimpleClutterFilter());
CappedCylinder cappedCyl = new CappedCylinder(LatLon.fromDegrees(27, -100), 3000000);
cappedCyl.getAttributes().setDrawInterior(true);
cappedCyl.getAttributes().setInteriorMaterial(Material.GREEN);
cappedCyl.getAttributes().setInteriorOpacity(.75f);
cappedCyl.setAltitudes(10, 100000);
RenderableLayer renderLayer = new RenderableLayer();
renderLayer.addRenderable(cappedCyl);
insertBeforeCompass(this.getWwd(), renderLayer);
// Create example annotations
this.setupAnnotations();
}
private void setupAnnotations() {
// Create an AnnotationLayer with lots of annotations
this.layer = new AnnotationLayer();
GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
ga.getAttributes().setTextColor(Color.white);
ga.getAttributes().setBackgroundColor(Color.BLACK);
ga.getAttributes().setOpacity(.75f);
ga.setAlwaysOnTop(true);
layer.addAnnotation(ga);
ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
ga.getAttributes().setTextColor(Color.white);
ga.getAttributes().setBackgroundColor(Color.BLACK);
ga.getAttributes().setOpacity(.75f);
ga.setAlwaysOnTop(true);
layer.addAnnotation(ga);
// Add layer to the layer list and update the layer panel
insertBeforeCompass(this.getWwd(), layer);
}
}
public static void main(String[] args) {
ApplicationTemplate.start("WorldWind Annotations", AppFrame.class);
}
}
Here is my (essentially no-op) Clutter Filter:
package gov.nasa.worldwindx.examples;
import java.util.List;
import gov.nasa.worldwind.render.Declutterable;
import gov.nasa.worldwind.render.DrawContext;
import gov.nasa.worldwind.util.ClutterFilter;
public class SimpleClutterFilter implements ClutterFilter{
#Override
public void apply(DrawContext dc, List<Declutterable> shapes) {
for(Declutterable shape: shapes) {
dc.addOrderedRenderable(shape);
}
}
}
And I also had to update the gov.nasa.worldwind.render.BasicAnnotationRenderer to have the OrderedAnnotations it creates implement Declutterable. (The only change to this inner class was adding isEnableDecluttering and getBounds):
public class OrderedAnnotation implements OrderedRenderable, Declutterable
{
protected Annotation annotation;
protected double eyeDistance;
protected Layer layer;
public OrderedAnnotation(Annotation annotation, double eyeDistance)
{
this.annotation = annotation;
this.eyeDistance = eyeDistance;
}
public OrderedAnnotation(Annotation annotation, Layer layer, double eyeDistance)
{
this.annotation = annotation;
this.eyeDistance = eyeDistance;
this.layer = layer;
}
public double getDistanceFromEye()
{
return this.eyeDistance;
}
public void render(DrawContext dc)
{
OGLStackHandler stackHandler = new OGLStackHandler();
BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
try
{
this.doRender(dc, this);
// Draw as many as we can in a batch to save ogl state switching.
while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
{
OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
this.doRender(dc, oa);
}
}
catch (WWRuntimeException e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
}
catch (Exception e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhileRenderingAnnotation", e);
}
finally
{
BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
}
}
public void pick(DrawContext dc, java.awt.Point pickPoint)
{
OGLStackHandler stackHandler = new OGLStackHandler();
BasicAnnotationRenderer.this.pickSupport.clearPickList();
BasicAnnotationRenderer.this.beginDrawAnnotations(dc, stackHandler);
try
{
this.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
this.doRender(dc, this);
// Draw as many as we can in a batch to save ogl state switching.
while (dc.peekOrderedRenderables() instanceof OrderedAnnotation)
{
OrderedAnnotation oa = (OrderedAnnotation) dc.pollOrderedRenderables();
oa.annotation.setPickSupport(BasicAnnotationRenderer.this.pickSupport);
this.doRender(dc, oa);
}
}
catch (WWRuntimeException e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
}
catch (Exception e)
{
Logging.logger().log(Level.SEVERE, "generic.ExceptionWhilePickingAnnotation", e);
}
finally
{
BasicAnnotationRenderer.this.endDrawAnnotations(dc, stackHandler);
BasicAnnotationRenderer.this.pickSupport.resolvePick(dc, pickPoint, this.layer);
BasicAnnotationRenderer.this.pickSupport.clearPickList(); // to ensure entries can be garbage collected
}
}
protected void doRender(DrawContext dc, OrderedAnnotation oa)
{
// Swap the draw context's current layer with that of the ordered annotation
Layer previousCurrentLayer = dc.getCurrentLayer();
try
{
dc.setCurrentLayer(oa.layer);
oa.annotation.renderNow(dc);
}
finally
{
dc.setCurrentLayer(previousCurrentLayer); // restore the original layer
}
}
#Override
public boolean isEnableDecluttering() {
return (annotation instanceof GlobeAnnotation);
}
#Override
public Rectangle2D getBounds(DrawContext dc) {
if(annotation instanceof GlobeAnnotation) {
return ((GlobeAnnotation) annotation).computeBounds(dc);
}
return null;
}
}
First of all;
Draw order of PointPlacemarks
https://forum.worldwindcentral.com/forum/world-wind-java-forums/development-help/13263-layer-priority-order
In setupAnnotations method, you set alwaysOnTop as true for both GlobeAnnotation objects. This might be the reason.
private void setupAnnotations() {
// Create an AnnotationLayer with lots of annotations
this.layer = new AnnotationLayer();
GlobeAnnotation ga = new GlobeAnnotation("Annotation", Position.fromDegrees(20, -100.9, 1000));
ga.getAttributes().setTextColor(Color.white);
ga.getAttributes().setBackgroundColor(Color.BLACK);
ga.getAttributes().setOpacity(.75f);
**ga.setAlwaysOnTop(true);**
layer.addAnnotation(ga);
ga = new GlobeAnnotation("Annotation", Position.fromDegrees(25, -100.9, 1000));
ga.getAttributes().setTextColor(Color.white);
ga.getAttributes().setBackgroundColor(Color.BLACK);
ga.getAttributes().setOpacity(.75f);
**ga.setAlwaysOnTop(true);**
layer.addAnnotation(ga);
// Add layer to the layer list and update the layer panel
insertBeforeCompass(this.getWwd(), layer);
}
Instead of that, putting annotations that you want to be always on top into separate layer and remaining ones into another layer might be solution by using the links above.

LibGDX Gdxpay requestPurchase not working

I've implemented Gdxpay into my libgdx game but when I call requestPurchase(), nothing happens. I followed this tutorial https://github.com/libgdx/gdx-pay/wiki/Integration-example-with-resolvers but I'm not sure where I'm going wrong.
Here is the main game class where the purchase observer is:
public MyGame extends Application adapter {
public MyGame(IActivityRequestHandler handler) {
// TODO Auto-generated constructor stub
super();
myRequestHandler = handler;
// ---- IAP: define products ---------------------
purchaseManagerConfig = new PurchaseManagerConfig();
purchaseManagerConfig.addOffer(new Offer().setType(OfferType.ENTITLEMENT).setIdentifier(SKU_REMOVE_ADS));
}
public PurchaseObserver purchaseObserver = new PurchaseObserver() {
#Override
public void handleRestore (Transaction[] transactions) {
for (int i = 0; i < transactions.length; i++) {
if (checkTransaction(transactions[i].getIdentifier()) == true) break;
}
// to make a purchase (results are reported to the observer)
PurchaseSystem.purchase(SKU_REMOVE_ADS);
}
#Override
public void handleRestoreError (Throwable e) {
// getPlatformResolver().showToast("PurchaseObserver: handleRestoreError!");
Gdx.app.log("ERROR", "PurchaseObserver: handleRestoreError!: " + e.getMessage());
throw new GdxRuntimeException(e);
}
#Override
public void handleInstall () {
// getPlatformResolver().showToast("PurchaseObserver: installed successfully...");
Gdx.app.log("handleInstall: ", "successfully..");
}
#Override
public void handleInstallError (Throwable e) {
//getPlatformResolver().showToast("PurchaseObserver: handleInstallError!");
Gdx.app.log("ERROR", "PurchaseObserver: handleInstallError!: " + e.getMessage());
throw new GdxRuntimeException(e);
}
#Override
public void handlePurchase (Transaction transaction) {
checkTransaction(transaction.getIdentifier());
}
#Override
public void handlePurchaseError (Throwable e) {
if (e.getMessage().equals("There has been a Problem with your Internet connection. Please try again later")) {
// this check is needed because user-cancel is a handlePurchaseError too)
// getPlatformResolver().showToast("handlePurchaseError: " + e.getMessage());
}
throw new GdxRuntimeException(e);
}
#Override
public void handlePurchaseCanceled () {
}
};
protected boolean checkTransaction (String ID) {
boolean returnbool = false;
if (SKU_REMOVE_ADS.equals(ID)) {
myRequestHandler.showAds(false);
returnbool = true;
}
return returnbool;
}
public void create() {
...
Here is where requestPurchase is called:
public class MainMenu extends Screen {
#Override
public void update() {
...
if (removeBounds.contains(touchPoint.x, touchPoint.y)) {
MyGame.getPlatformResolver().requestPurchase(MyGame.SKU_REMOVE_ADS);
}
}
...
}
Many thanks.
Edit: Ok logcat says the following error when I request a purchase:
5188-5220/com.comp.myGame.android I/ERRORīš• gdx-pay: requestPurchase(): purchaseManager == null
So that means pruchaseManager is null, but according to the tutorial in this instance it should cause the correct purchaseManager to be called so I'm still confused...
I had exactly the same issue. I followed the tutorial as well, but changed the distributed resolver system to a more local defined system where all app store keys are set in the main game class.
This didn't work (with the same error you got). I then re-engineered the code to follow exactly the tutorial - with all the resolver bells and whistles. Next, I got a "no suitable app store found" error while creating the purchaseManager (at this point, I celebrated because it at least TRIED to create it).
I think that it worked the second try has something to do with the sequence flow:
In the android/AndroidLauncher.java, onCreate:
MyGame myGame = new MyGame(this);
initialize(myGame, config);
// init IAP
myGame.setPlatformResolver(new AndroidResolver(myGame, this));
In core/MyGame.java, declarations:
public PurchaseObserver purchaseObserver = new BrainsPurchaseObserver();
public PurchaseManagerConfig purchaseManagerConfig;
In core/MyGame.java, constructor:
purchaseManagerConfig = new PurchaseManagerConfig();
Offer iap15Tipps = new Offer();
iap15Tipps.setIdentifier(Product.brains_hints_15.name());
iap15Tipps.setType(OfferType.CONSUMABLE);
purchaseManagerConfig.addOffer(iap15Tipps);
PlatformResolver.java and AndroidResolver.java as described in the tutorial. This worked to the point of the above error "no app store found".
Then I switched from gdx-pay 0.3.0 to 0.4.0 (by just incrementing the version in the gradle settings, it is already available in the repository), AND IT WORKED!
I suggest you check the sequence of IAP initializing you execute and switch to 0.4.0 if you are not already using it.
-- Michael

java.lang.reflect.InvocationTargetException whilst locally running an applet (no server)

I'm trying to load an applet on a simple HTML page that I've written (I also wrote the applet) but it throws an InvocationTargetException every time. The applet works when I run it in Eclipse, but I can't get it to work on the webpage.
HTML:
<html>
<center>
<applet archive = "OneMove.jar" code = "main.TheApplet.class" width = "1000" height = "500"></applet>
</center>
</html>
TheApplet.class:
package main;
import java.awt.BorderLayout;
import java.lang.reflect.InvocationTargetException;
import javax.swing.*;
public class TheApplet extends JApplet {
private static final long serialVersionUID = 7088647188194272265L;
protected Display display0 = new Display();
public void init() {
try {
SwingUtilities.invokeAndWait(new Runnable() {
public void run() {
setLayout(new BorderLayout());
add(display0);
}
});
} catch (InvocationTargetException e) {
e.printStackTrace();
e.getCause();
} catch (InterruptedException e) {
e.printStackTrace();
}
}
public void start() {
display0.start();
}
public void stop() {
display0.stop();
}
}
If there's any other piece of code you need from me, just ask and I will post.
Need an answer sooner rather than later, too:p
Thanks all!
If you compiled you applet with jdk 1.6 you must use jre 6 for browser.

Categories

Resources