You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在LibGDX开发的Facebook Instant Game中集成排行榜与应用内广告

Injecting JavaScript into LibGDX/GWT for Facebook Instant Games Features

Absolutely! You don’t need to dig through GWT’s obfuscated compiled JavaScript to add Facebook Instant Games features like ads and leaderboards to your GameOver screen. GWT provides two reliable ways to integrate custom JavaScript directly into your Java code—these methods will compile alongside your game logic seamlessly. Let’s break down both approaches with examples tailored to your use case:

Method 1: JSNI (JavaScript Native Interface) – Quick & Straightforward

JSNI lets you embed raw JavaScript directly in Java methods using a special syntax. It’s ideal for quick integrations where you just need to call existing FB Instant Games SDK functions.

Step 1: Create a Java Utility Class with JSNI Methods

Make a new class (e.g., FBInstantUtils.java) in your GWT project’s source folder, and add native methods for ads and leaderboards:

package com.yourgame.gwt;

import com.google.gwt.user.client.Window;

public class FBInstantUtils {

    // Show interstitial ad when GameOver screen loads
    public static native void showInterstitialAd() /*-{
        if (!$wnd.FBInstant) {
            console.error("FBInstant SDK not loaded");
            return;
        }

        // Load and display ad (replace YOUR_PLACEMENT_ID with your actual ID)
        $wnd.FBInstant.getInterstitialAdAsync('YOUR_PLACEMENT_ID')
            .then(interstitial => interstitial.showAsync())
            .then(() => {
                console.log("Ad closed");
                // Trigger Java logic after ad closes
                @com.yourgame.gwt.FBInstantUtils::onAdClosed()();
            })
            .catch(error => console.error("Ad failed: ", error));
    }-*/;

    // Show leaderboard on button press
    public static native void showLeaderboard(String leaderboardId) /*-{
        if (!$wnd.FBInstant) {
            console.error("FBInstant SDK not loaded");
            return;
        }

        $wnd.FBInstant.getLeaderboardAsync(leaderboardId)
            .then(leaderboard => leaderboard.showAsync())
            .catch(error => console.error("Leaderboard failed: ", error));
    }-*/;

    // Java callback for post-ad actions (optional)
    public static void onAdClosed() {
        // Add game logic here, like returning to main menu
        Window.alert("Ad closed! Ready to play again?");
        // Or call your LibGDX game's method:
        // YourGame.getInstance().switchToMainMenu();
    }
}

Step 2: Call These Methods from Your GameOver Screen

In your LibGDX GameOverScreen.java, trigger these methods when the screen loads (or on button presses):

import com.badlogic.gdx.ApplicationType;
import com.badlogic.gdx.Gdx;
import com.badlogic.gdx.scenes.scene2d.ui.Button;
import com.badlogic.gdx.scenes.scene2d.utils.ClickListener;

public class GameOverScreen extends ScreenAdapter {
    private final YourGame game;

    public GameOverScreen(YourGame game) {
        this.game = game;
    }

    @Override
    public void show() {
        // Show ad when GameOver screen appears (only on web platform)
        if (Gdx.app.getType() == ApplicationType.WebGL) {
            FBInstantUtils.showInterstitialAd();
        }

        // Example: Show leaderboard when a button is clicked
        Button leaderboardButton = new Button(game.skin);
        leaderboardButton.addListener(new ClickListener() {
            @Override
            public void clicked(InputEvent event, float x, float y) {
                if (Gdx.app.getType() == ApplicationType.WebGL) {
                    FBInstantUtils.showLeaderboard("your_leaderboard_id");
                }
            }
        });
        // Add button to your screen's stage
        stage.addActor(leaderboardButton);
    }
}

Method 2: JsInterop – Modern & Type-Safe

JsInterop is the recommended approach for GWT 2.8+. It provides type-safe access to JavaScript objects, making your code cleaner and easier to maintain.

Step 1: Map FBInstant SDK with JsInterop Annotations

Create interfaces to mirror the FBInstant SDK’s structure:

package com.yourgame.gwt;

import jsinterop.annotations.JsMethod;
import jsinterop.annotations.JsProperty;
import jsinterop.annotations.JsType;
import java.util.concurrent.CompletableFuture;

// Map the global FBInstant object
@JsType(isNative = true, namespace = JsType.GLOBAL)
public class FBInstant {
    @JsProperty
    public static boolean isInitialized;

    @JsMethod
    public static native CompletableFuture<Void> initializeAsync();

    @JsMethod
    public static native CompletableFuture<InterstitialAd> getInterstitialAdAsync(String placementId);

    @JsMethod
    public static native CompletableFuture<Leaderboard> getLeaderboardAsync(String leaderboardId);
}

// Map interstitial ad object
@JsType(isNative = true)
public interface InterstitialAd {
    CompletableFuture<Void> showAsync();
}

// Map leaderboard object
@JsType(isNative = true)
public interface Leaderboard {
    CompletableFuture<Void> showAsync();
}

Step 2: Build a Type-Safe Utility Class

Use the mapped interfaces to create a clean utility class:

package com.yourgame.gwt;

import java.util.concurrent.CompletableFuture;

public class FBInstantJsUtils {

    public static void showInterstitialAd(String placementId) {
        if (!FBInstant.isInitialized) {
            System.err.println("FBInstant not initialized");
            return;
        }

        FBInstant.getInterstitialAdAsync(placementId)
            .thenApply(InterstitialAd::showAsync)
            .thenRun(FBInstantJsUtils::onAdClosed)
            .exceptionally(error -> {
                System.err.println("Ad error: " + error.getMessage());
                return null;
            });
    }

    public static void showLeaderboard(String leaderboardId) {
        if (!FBInstant.isInitialized) {
            System.err.println("FBInstant not initialized");
            return;
        }

        FBInstant.getLeaderboardAsync(leaderboardId)
            .thenApply(Leaderboard::showAsync)
            .exceptionally(error -> {
                System.err.println("Leaderboard error: " + error.getMessage());
                return null;
            });
    }

    private static void onAdClosed() {
        // Trigger game logic here
        System.out.println("Ad closed! Returning to main menu...");
        YourGame.getInstance().switchToMainMenu();
    }
}

Step 3: Call from GameOver Screen

Just like with JSNI, call these methods with a platform check:

@Override
public void show() {
    if (Gdx.app.getType() == ApplicationType.WebGL) {
        FBInstantJsUtils.showInterstitialAd("your_ad_placement_id");
    }

    // Leaderboard button example
    Button leaderboardButton = new Button(game.skin);
    leaderboardButton.addListener(new ClickListener() {
        @Override
        public void clicked(InputEvent event, float x, float y) {
            if (Gdx.app.getType() == ApplicationType.WebGL) {
                FBInstantJsUtils.showLeaderboard("your_leaderboard_id");
            }
        }
    });
    stage.addActor(leaderboardButton);
}

Key Tips for Success

  • Platform Check: Always wrap web-specific calls in Gdx.app.getType() == ApplicationType.WebGL to avoid errors on desktop/mobile builds.
  • Initialization Confirmation: Ensure FBInstant.initializeAsync() and startGameAsync() have completed before calling ad/leaderboard functions (your existing main.js handles this, but you can add a flag if needed).
  • Replace Placeholder IDs: Swap YOUR_PLACEMENT_ID and your_leaderboard_id with your actual IDs from the Facebook Developer Dashboard.

内容的提问来源于stack exchange,提问作者Harry

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.04.30 15:22:49