简体   繁体   中英

How to use Facebook Instant Games Leaderboards and In-App Ads with LibGDX

I would like to make my LibGDX game work as a Facebook instant game. So far I have managed to set up the game client as shown in the quick start guide like this:

<!DOCTYPE html>
<html>
  <head>
    <title>My LibGDX Game</title>
    <meta http-equiv="content-type" content="text/html; charset=UTF-8" />
    <meta
      id="gameViewport"
      name="viewport"
      content="width=device-width initial-scale=1"
    />
    <meta name="apple-mobile-web-app-capable" content="yes" />
    <meta name="full-screen" content="yes" />
    <meta name="screen-orientation" content="portrait" />
  </head>

  <body>
    <div align="center" id="embed-html"></div>
    <script src="https://connect.facebook.net/en_US/fbinstant.6.3.js"></script>
    <script src="main.js"></script>
    <script type="text/javascript" src="html/html.nocache.js"></script>
  </body>

  <script>
    function handleMouseDown(evt) {
      evt.preventDefault();
      evt.stopPropagation();
      window.focus();
    }
    function handleMouseUp(evt) {
      evt.preventDefault();
      evt.stopPropagation();
    }
    document
      .getElementById("embed-html")
      .addEventListener("mousedown", handleMouseDown, false);
    document
      .getElementById("embed-html")
      .addEventListener("mouseup", handleMouseUp, false);
  </script>
</html>

In my main.js file which is separate from the GWT generated JS code, I am able to use the Facebook Instant games SDK to get the username and ID like this:

FBInstant.initializeAsync().then(function () {
  var progress = 0;

  var interval = setInterval(function () {
    progress += 3;
    FBInstant.setLoadingProgress(progress);

    if (progress >= 99) {
      clearInterval(interval);
      FBInstant.startGameAsync().then(function () {
        console.log("shit stsrted");
        var playerId = FBInstant.player.getID(); // Get Facebook ID
        var playerName = FBInstant.player.getName(); // Get Facebook Name
        console.log(playerId);
        console.log(playerName);
      });
    }
  }, 100);
  console.log("loaded");
});

Now I need to show an Ad and leaderboard on the GameOver screen, but how can I add Leaderboards and In-App Ads If the code for that is in JavaScript? I tried to dig into the GWT compiled JS code to somehow find the GameOver function but that code is unreadable. Is there a way to do this in the Java code maybe inject JavaScript and let GWT compile it with Java?

GWT project supports calling native JS from Java, previously through JSNI which allowed you to write JavaScript as a comment in method in Java world, but now there is a better solution - JSInterop - http://www.gwtproject.org/doc/latest/DevGuideCodingBasicsJsInterop.html

I came across your question when learning about it myself, and this blog explained it well for my use case: https://lofidewanto.medium.com/learn-once-use-everywhere-javascript-in-java-for-web-browser-ec1b9657232c

Here's what I did: Libgdx is multiplatform and I want to preserve the ability to port my game to mobile platforms, so I create a Java interface that handles loading and displaying of Ads (interstitials and rewarded videos):

public interface AdRequestHandler {

    void loadInterstitial();
    void showInterstitial();
    void loadRewardedVideo();
    void showRewardedVideo();
}

My GWT/HTML will only target Facebook instant games, so I provide an implementation of above interface:

public class FacebookAdRequestHandler implements AdRequestHandler {

    private FacebookAdRequestService facebookAdRequestService = new FacebookAdRequestService();

    @Override
    public void loadInterstitial() {
        facebookAdRequestService .loadInterstitialImpl();
    }

    @Override
    public void showInterstitial() {
        facebookAdRequestHandlerNative.showInterstitialImpl();
    }

    @Override
    public void loadRewardedVideo() {
        facebookAdRequestService.loadRewardedVideoImpl();
    }

    @Override
    public void showRewardedVideo() {
        facebookAdRequestService.showRewardedVideoImpl();
    }

}

The implementation simply calls a Service class that does all the native JS calls:

@JsType(namespace = JsPackage.GLOBAL, name = "FacebookAdRequestHandler", isNative = true)
public class FacebookAdRequestService {

    public native void loadInterstitialImpl();
    public native void showInterstitialImpl();
    public native void loadRewardedVideoImpl();
    public native void showRewardedVideoImpl();
}

now for the JS part, I take your main.js file in the project under html/webapp

FBInstant.initializeAsync().then(function () {
  var progress = 0;

  var interval = setInterval(function () {
    progress += 3;
    FBInstant.setLoadingProgress(progress);

    if (progress >= 99) {
      clearInterval(interval);
      FBInstant.startGameAsync().then(function () {
        //var playerId = FBInstant.player.getID(); // Get Facebook ID
        //var playerName = FBInstant.player.getName(); // Get Facebook Name
      });
    }
  }, 100);
});

FacebookAdRequestHandler = function () {
    var preloadedInterstitial = null;
    var preloadedRewardedVideo = null;
}
FacebookAdRequestHandler.prototype.loadInterstitialImpl = function () {
    FBInstant.getInterstitialAdAsync(
      '123123123123_123123123123' // Your Ad Placement Id
    ).then(function(interstitial) {
      // Load the Ad asynchronously
      preloadedInterstitial = interstitial;
      return preloadedInterstitial.loadAsync();
    }).then(function() {
      console.log('Interstitial preloaded');
    }).catch(function(err){
      console.error('Interstitial failed to preload: ' + err.message);
    });
}
FacebookAdRequestHandler.prototype.showInterstitialImpl = function () {
    preloadedInterstitial.showAsync()
    .then(function() {
      // Perform post-ad success operation
      console.log('Interstitial ad finished successfully');
    })
    .catch(function(e) {
      console.error(e.message);
    });
}
FacebookAdRequestHandler.prototype.loadRewardedVideoImpl = function () {
     FBInstant.getRewardedVideoAsync(
      '456456456456_456456456456' // Your Ad Placement Id
    ).then(function(rewarded) {
      // Load the Ad asynchronously
      preloadedRewardedVideo = rewarded;
      return preloadedRewardedVideo.loadAsync();
    }).then(function() {
      console.log('Rewarded video preloaded');
    }).catch(function(err){
      console.error('Rewarded video failed to preload: ' + err.message);
    });
}
FacebookAdRequestHandler.prototype.showRewardedVideoImpl = function () {
    preloadedRewardedVideo.showAsync()
    .then(function() {
      // Perform post-ad success operation
      console.log('Rewarded video watched successfully');
    })
    .catch(function(e) {
      console.error(e.message);
    });
}

I've taken the code for loading and showing the interstitial directly from FB's documentation for their Instant Games - In-App Ads for Instant Games And I've actually taken your example to resolve an issue of initializing and going around the progress bar reporting.

I've tested it for interstitials so far and that displays the ad correctly. What needs work is making sure to only display the ad when it loaded (maybe just do a null check inside showInterstitialImpl . Now this is only a one sided solution, it doesn't report back to the Java part that anything was displayed, you can do that as well using @JsFunction annotation to create some callbacks

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM