• Hey Guest! Ever feel like entering a Game Jam, but the time limit is always too much pressure? We get it... You lead a hectic life and dedicating 3 whole days to make a game just doesn't work for you! So, why not enter the GMC SLOW JAM? Take your time! Kick back and make your game over 4 months! Interested? Then just click here!
  • Hello [name]! Thanks for joining the GMC. Before making any posts in the Tech Support forum, can we suggest you read the forum rules? These are simple guidelines that we ask you to follow so that you can get the best help possible for your issue.

Android Gradle build with Google Firebase

clee2005

Member
I managed to get Firebase Crashlytics to build but I have to put the "google-services.json" in the android/runner/project folder for it to get picked up by the build. This is fine for this one app... I'd rather not have to switch this file out for each build of different apps. Is there a place to put this file where it will belong to the GMS2 project and get seen by the Gradle build?

Thanks,
Chris
 

clee2005

Member
I have another issue where I have api_key.txt for Amazon Login. I'm using it for Amazon Underground and Amazon App store. I need to swap this file out in the Included Files folder of the IDE before each build since it's the same filename. What would be nice is a pre-build macro or process that could be kicked off... simple as executing a batch file or something before the build is run ... this could solve both problems and many others I'm sure.
 
A

Animus Audax

Guest
Anybody solved this issue with swapping "google-services.json" ?
Maybe it's possible to change names that Firebase is looking for?
 

Mert

Member
Anybody solved this issue with swapping "google-services.json" ?
Maybe it's possible to change names that Firebase is looking for?
I've successfully ported Crashlytics and Performance Monitoring along with Remote Configurations, Analytics and Firestore. Also be impletementing Machine Learning kits once I have some free time.

Currently, there's no way to change google-services.json file on GMS2 IDE. You'd have to manually put it on (The folder is for me, but should be same for you too) Program Data folder is hidden, so you have to set Windows to see hidden files.

C:/Program Data/GameMakerStudio2/Cache/runtimes/runtime-2.2.0.261/android/runner/ProjectFiles/

Check the runtime you use on GMS2 IDE, that's the folder you're going to put it on.
 

Mert

Member
++
Things so far I've discovered.

ANALYTICS
When I switch to another room in my app, Firebase logs that as "user_engagement" as if it switches to another Activity. (perhaps it does). I want to set the current screen to log in Firebase, but Game Maker creates random screen ID for each room, just makes the analytics too unreadable for this. Firebase docs implies that you can set screens manually, but has to be called from Main Thread. Here's how I did that. Put it on Room's Creation Code.

AnalyticsSetCurrentScreen("Main Menu"); for example

mFirebaseAnalytics is set when I call the function AnalyticsInit
mFirebaseAnalytics = FirebaseAnalytics.getInstance(RunnerActivity.CurrentActivity.getApplicationContext());
Code:
public void AnalyticsSetCurrentScreen(final String arg0) {
    
        RunnerActivity.CurrentActivity.runOnUiThread(new Runnable() {
        @Override
        public void run() {
          mFirebaseAnalytics.setCurrentScreen(RunnerActivity.CurrentActivity, arg0, null);
        }//public void run() {
        });
    }
However, it logs two events on analytics. One : When Game Maker changes the room(with random room ID), and this one where you can see screen name properly. Not looks neat, but does the job. Best option is to avoid changing rooms(use one room throughout the game)

PERFORMANCE MONITORING
It can track basics, like network timing and the time it takes to open the application etc. I can't do custom traces since Game Maker builds the game with its library, and anything you put on, let's say CREATE EVENT, may be put on another part of the final java file. I'll need more information from Yoyogames about how Yoyogames do these stuff.

CRASHLYTICS
Game Maker doesn't use proguard, so I wouldn't need mapping etc. The only issue with this is that we don't have try <> catch <> exception, as Crashlytics can capture exceptions and log those on Firebase panel. Even though I've seen posts from Yoyogames to bring exception to Game Maker, I don't know whether we can use this feature with Crashlytics.

REMOTE CONFIGURATIONS
All works perfectly. The only issue is the tiny tiny data conversion issue where Game Maker can only pass either string or double to/from java file. I use long and boolean too. I have Social Async call once the remote configurations are loaded, and can get these values non-async.

CLOUD MESSAGING
I've managed to receive Cloud Messages from Firebase panel to Game Maker, but didn't have much time to do further. I'm planning to complete it and get notifications etc.

EDIT : I've managed to send remote push notifications successfully. It also tracks how many devices received the notification and how many of them opened it.

CLOUD STORAGE
Must not be too hard, also on my list.

EDIT : FIRESTORE
Basically the easiest one I've approached. I successfully implemented real-time document listening so I receive updates(almost instantly although I live in Turkey and the database is in US-Central). I can therefore do something like chat application or turn based games.

I am planning to create a tutorial here. I also currently use Firebase remote configurations and features in my Android app Flax
 
Last edited:

clee2005

Member
@Mert thanks for this posting! I was looking for details on the screen name in Firebase.

I also rigged up a .vbs scripting setup for my apps which allows me to switch out the Firebase google-services.json and GoogleService-info.plist (iOS) as well as any other changes to the GMS runtimes that are needed. I installed a PS Hot Launch utility which allows me to run the .vbs script via CTRL-F12 (or anything you want to hotkey). So I do this just before I build and it brings up a little menu in .vbs script where I choose the app I'm building and it swaps everything as needed. This will do until YoYo adds the ability to inject pre-build changes of our own.

Main Script
Code:
dim runtime,androidRootFiles,androidProjectSourceMain,androidProjectXML,rootPath,isAmazon,androidProjectFiles,admobAppId
runtime = "2.2.1.291"

if WScript.Arguments.Count = 0 then
    WScript.Echo "Missing parameters"
    wscript.quit
end if

Const ForReading = 1
Const ForWriting = 2

androidRootFiles = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\android\runner\RootFiles"
androidProjectSourceMain = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\android\runner\ProjectFiles\src\main"
androidProjectFiles = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\android\runner\ProjectFiles"
androidProjectXML = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\android\runner\ProjectFiles\src\main\res\xml"
androidRunner = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\android\runner\ProjectFiles\src\main\java\YYAndroidPackageDomain\YYAndroidPackageCompany\YYAndroidPackageProduct"
iosProjectRoot = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\ios\TemplateProject\${YYXCodeProjName}"
iosProjectFile = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\ios\TemplateProject\${YYXCodeProjName}.xcodeproj"
iosFoldersRoot = "C:\ProgramData\GameMakerStudio2\Cache\runtimes\runtime-" & runtime & "\ios\TemplateProject"

rootPath = WScript.Arguments(0)    ' The Path of the GMS projet where the expected files exist
isAmazon = WScript.Arguments(1)       ' If True indicates we are building for the Amazon store
admobAppId = WScript.Arguments(2)  ' The Admob ID to update the Appodeal manifest
langs = WScript.Arguments(3)       ' The iOS languages to support 'ES,FR'

Dim fso
Set fso = CreateObject("Scripting.FileSystemObject")

dim scriptdir
scriptdir = fso.GetParentFolderName(WScript.ScriptFullName)

' If the network_security_config.xml file is not in place then run the following one time copy instructions
If (not Fso.FileExists(androidProjectXML & "\network_security_config.xml")) Then
   
    ' Copy Resources folder for Appodeal
    Fso.CopyFolder scriptdir & "\Resources", iosFoldersRoot & "\Resources"  
   
    ' Copy the network_security_config.xml and AndroidManifest.xml
    Fso.CopyFile scriptdir & "\network_security_config.xml", androidProjectXML & "\network_security_config.xml"
    Fso.CopyFile scriptdir & "\AndroidManifest.xml", androidProjectSourceMain & "\AndroidManifest.xml"
   
    ' Create the French and Spanish languages (even though we may only use one or both)
    Fso.CopyFolder iosProjectRoot & "\en.lproj", iosProjectRoot & "\es.lproj"
    Fso.CopyFolder iosProjectRoot & "\en.lproj", iosProjectRoot & "\fr.lproj"
   
    ' Copy modifications to the Android Runner
    Fso.CopyFile scriptdir & "\RunnerActivity.java", androidRunner & "\RunnerActivity.java"
   
    MsgBox("Copied : " + chr(13) + "RunnerActivity.java" + chr(13) + "Appodeal Resources folder" + chr(13) + "network_security_config.xml" + chr(13) + "AndroidManifest.xml" + chr(13) + "fr.lproj (ios)" + chr(13) + "es.lproj" + chr(13) + "Runtime : " & runtime )
       
end if

' Copy the gradle modified files
Fso.CopyFile scriptdir & "\root-build.gradle", androidRootFiles & "\build.gradle"
Fso.CopyFile scriptdir & "\project-build.gradle", androidProjectFiles & "\build.gradle"

' Modify the Appodeal manifest which includes the ADMOB ApplicationID
dim first,second
Set objFile = Fso.OpenTextFile(rootPath & "\extensions\AppodealAds\AppodealAds.yy", ForReading)
strText = objFile.ReadAll
objFile.Close
first = Left(strText,InStr(strText,"ca-app-pub-XXXXXXX~")-1) ' This is the admob id which is the same for all apps replace XXXXXXX with your actual admob publisher id
second = Mid(strText,InStr(strText,"ca-app-pub-XXXXXX~"))
second = Mid(second, InStr(second,"\"))
strNewText = first & admobAppId & second
Set objFile = Fso.OpenTextFile(rootPath & "\extensions\AppodealAds\AppodealAds.yy", ForWriting)
objFile.WriteLine strNewText
objFile.Close


'''''''''''''''''
' iOS
'''''''''''''''''

' Copy the GoogleService-Info.plist to iOS
Fso.CopyFile rootPath & "\GoogleService-Info.plist", iosProjectRoot & "\GoogleService-Info.plist"

' Copy the project.pbxproj to iOS - Then modify to replace the languages to be used
Fso.CopyFile scriptdir & "\project.pbxproj", iosProjectFile & "\project.pbxproj"
Set objFile = Fso.OpenTextFile(iosProjectFile & "\project.pbxproj", ForReading)
strText = objFile.ReadAll
objFile.Close
strNewText = Replace(strText, "${AdditionalLanguages}", langs)
Set objFile = Fso.OpenTextFile(iosProjectFile & "\project.pbxproj", ForWriting)
objFile.WriteLine strNewText
objFile.Close


' Get Project Folder Name
dim projectName,store
projectName = Fso.getfolder(rootPath).Name

if (isAmazon) then
    Fso.CopyFile rootPath & "\google-services-amazon.json", androidProjectFiles & "\google-services.json"
   
    ' Copy the Amazon Login api_key
    Fso.CopyFile rootPath & "\api_key_amazon.txt", rootPath & "\datafiles\api_key.txt"
   
    store = "AMAZON"
else
    Fso.CopyFile rootPath & "\google-services.json", androidProjectFiles & "\google-services.json"
   
    ' Copy the Amazon Login api_key
    Fso.CopyFile rootPath & "\api_key_googleplay.txt", rootPath & "\datafiles\api_key.txt"
   
    store = "Google Play"
end if
MsgBox("Project : " & projectName & chr(13) & "Runtime : " & runtime & chr(13) & chr(13) & "Android : " & store)
Then in each project folder (where the google-services.json and other specific files are expected to be) you'll have this .vbs which sends the specific information to the above script.

Code:
' This is the specific script to be launched from each project folder
Dim fso,admobAppId,parentFolder,scriptdir
admobAppId = "ca-app-pub-XXXXX~XXXXXX"

Set fso = CreateObject("Scripting.FileSystemObject")
scriptdir = fso.GetParentFolderName(WScript.ScriptFullName)
parentFolder = fso.GetParentFolderName(scriptdir)

Dim objShell
Set objShell = Wscript.CreateObject("WScript.Shell")

' Params
' 1 - This script path
' 2 - IsAmazon Build (true/false)
' 3 - Admob App ID
' 4 - Languages supported (fr,es)

objShell.Run parentFolder + "\Build\SetGMSBuild.vbs " & scriptdir & " false " & admobAppId & " fr,es,"

' Using Set is mandatory
Set objShell = Nothing
Then you just need to call the project specific .vbs file right before you build and it'll ensure that your runtime is ready to go. Also when YoYo updates the Runtime this same script will ensure that all the alterations to the Runtime (long term modifications) are put back in place. I'm using Appodeal for mediation so I have changes for that and for iOS additional languages to the XCode project. Just remove those as you see fit.

I hope some of that is useful to someone.

Cheers,
Chris
 
Last edited:

Mert

Member
@clee2005 thanks, sounds absolutely delicious!

I'll also work on Machine Learning kits (perhaps the visualise tools first). My intention is to make a game that is something like;
  • You get a keyword of an object/animal/food anything.. (Pencil for example)
  • You must draw this on screen to explain it to other players.
  • Check the screen if it looks like pencil(I have zero idea if currently premade tools are capable of doing this, but they should be)
  • If it checks, award the player a point.
 

chirpy

Member
I was able to put google-services.json in my project's "Included Files" and then add a gradle task to automatically move the .json file to appropriate folder location when building.
For iOS, I haven't checked yet, but I run a ruby script to modify generated .xcodeproj and use CocoaPods, so I'd assume I can do similar as clee2005 does in the vb script.

Here's my gradle dependencies injection for whoever needed.
Only tested in gradle plugin 3.6.1 and gradle 5.6.4, where I had to add another task to rename output .aab.

Code:
} // close previous dependencies injections

apply plugin: 'com.google.gms.google-services'

tasks.whenTaskAdded { task ->
    if (task.name.startsWith("process") &&
        task.name.endsWith("GoogleServices")) { // processDebugGoogleServices, processReleaseGoogleServices
        def prepTaskName = task.name.replace("process", "prepare") // prepareDebugGoogleServices
        def flavorSuffix = task.name.substring("process".length()).replace("GoogleServices", "").uncapitalize() // "debug"
        def prepTask = tasks.create(prepTaskName) {
            def dstPath = "$projectDir"
            def srcFile = "$projectDir/src/main/assets/google-services.json"
            println "Hello $flavorSuffix google-services.json -> $dstPath"
            ant.move file: srcFile,
                            todir: dstPath,
                            failonerror: false // to ignore 2nd move that always fails
        }
        task.dependsOn prepTask
        task.mustRunAfter prepTask
    }
}

// start a new dependencies section
dependencies
{
    implementation 'com.google.firebase:firebase-analytics:17.3.0'
 
Top