Blank Screen on Android, Runs on IOS

I have made a game and released it on iOS and now I am trying to build it for Android and I can’t get it to run at all.  I am using a 2013 Nexus 7 (the newest one) to test it on.  When I run it I see the splash screen and then the screen just goes black.  The app doesn’t crash, it just sits there showing a black screen.  To test I have swapped out the first composer scene (“menu”) with a hello world scene that I have successful run standalone so I know the problem (or at least the first problem) is in my main file.  See below the log output from the android device and my main file (apologies - its pretty messy because I am doing ads and notifications etc in there as well).  Appreciate any help you can give me!

Log:

V/Corona  (19307): > Class.forName: network.LuaLoader

V/Corona  (19307): < Class.forName: network.LuaLoader

V/Corona  (19307): Loading via reflection: network.LuaLoader

I/Corona  (19307): Platform: Nexus 7 / ARM Neon / 4.3 / Adreno ™ 320 / OpenGL ES 3.0 V@14.0 AU@  (CL@) / 2014.2393

V/Corona  (19307): > Class.forName: CoronaProvider.licensing.google.LuaLoader

V/Corona  (19307): < Class.forName: CoronaProvider.licensing.google.LuaLoader

V/Corona  (19307): Loading via reflection: CoronaProvider.licensing.google.LuaLoader

I/Corona  (19307): [Lua::RuntimeDispatchEvent()] WARNING: This function is deprecated. Use Lua::DispatchRuntimeEvent() instead.

Main File:

display.setStatusBar(display.HiddenStatusBar) local composer = require( "composer") if "Android" == system.getInfo( "platformName" ) then return true else require('audio') if audio.supportsSessionProperty then audio.setSessionProperty(audio.MixMode, audio.AmbientMixMode) end end require( "ice" ) composer.multiTouch = require("dmc\_multitouch") --was composer.MultiTouch system.activate("multitouch") local gameNetwork = require "gameNetwork" local ads = require( "ads" ) local thisRate = ice:loadBox( "myRate" ); local analytics = require "analytics" local facebook = require( "facebook" ) local widget = require( "widget" ) local connection = require( "connection" ) if ( system.getInfo( "platformName" ) == "Android" ) then local store = require( "plugin.google.iap.v3" ) elseif ( system.getInfo( "platformName" ) == "iPhone OS" ) then local store = require( "store" ) end customVar = {} composer.volumeSwitch = thisRate:retrieve( "volumeSwitch" ); composer.currScene = composer.getSceneName("current") composer.gameOver = false composer.pushMessage = false composer.noAdsAdClicked = false composer.run = false composer.textScaleFactor = 2 composer.restart = false composer.firstRun = true composer.appSuspend = false composer.autoRestartNum = 0 composer.showingAd = false composer.reboot = false composer.popup = false composer.newStoreItem = false local chooseAd = 0 local cancelNotify local noAdsAd local adPlaceholder --[[if ( system.getInfo("environment") =="simulator" ) then local function monitorMem() collectgarbage() print( "MemUsage: " .. collectgarbage("count") ) local textMem = system.getInfo( "textureMemoryUsed" ) / 1000000 print( "TexMem: " .. textMem ) end Runtime:addEventListener("enterFrame", monitorMem) end]] function DidReceiveRemoteNotification(message, additionalData, isFirstOpen) analytics.logEvent( "Recieved GameThrive Push Notification" ) if (additionalData and additionalData.newStoreItem) then composer.pushMessage = message composer.newStoreItem = true end end local launchArgs = ... local GameThrive = require ( "plugin.GameThrivePushNotifications" ) GameThrive.HandleLaunchArgs(launchArgs, "###############", DidReceiveRemoteNotification) local mainGroup = display.newGroup() -- Main function local function main() io.output():setvbuf('no') analytics.init( "###############" ) facebook.publishInstall( "##############") --print(1/display.contentScaleX, 1/display.contentScaleY) composer.difficulty = thisRate:retrieve( "difficulty" ) if composer.difficulty == nil then composer.difficulty = 2 end composer.arLevel = thisRate:retrieve( "arLevel" ) if composer.arLevel == nil then composer.arLevel = 40 end composer.pause = thisRate:retrieve( "savedpause" ) if composer.pause == nil then composer.pause = false end composer.volumeSwitch = thisRate:retrieve( "volumeSwitch" ) if composer.volumeSwitch == nil then composer.volumeSwitch = true end composer.removeAdsIAP = thisRate:retrieve( "removeAdsIAP" ) if composer.removeAdsIAP == nil then composer.removeAdsIAP = false end composer.extraLifeIAP = thisRate:retrieve( "extraLifeIAP" ) if composer.extraLifeIAP == nil then composer.extraLifeIAP = false end composer.blueThemeIAP = thisRate:retrieve( "blueThemeIAP" ) if composer.blueThemeIAP == nil then composer.blueThemeIAP = false end customVar.blueThemeSelected = thisRate:retrieve( "blueThemeSelected" ) if customVar.blueThemeSelected == nil then customVar.blueThemeSelected = false end composer.purpleThemeIAP = thisRate:retrieve( "purpleThemeIAP" ) if composer.purpleThemeIAP == nil then composer.purpleThemeIAP = false end customVar.purpleThemeSelected = thisRate:retrieve( "purpleThemeSelected" ) if customVar.purpleThemeSelected == nil then customVar.purpleThemeSelected = false end composer.pinkThemeIAP = thisRate:retrieve( "pinkThemeIAP" ) if composer.pinkThemeIAP == nil then composer.pinkThemeIAP = false end customVar.pinkThemeSelected = thisRate:retrieve( "pinkThemeSelected" ) if customVar.pinkThemeSelected == nil then customVar.pinkThemeSelected = false end customVar.originalThemeSelected = thisRate:retrieve( "originalThemeSelected" ) if customVar.originalThemeSelected == nil then customVar.originalThemeSelected = false end if customVar.originalThemeSelected then customVar.selectedTheme = "Green" elseif customVar.blueThemeSelected then customVar.selectedTheme = "Blue" elseif customVar.purpleThemeSelected then customVar.selectedTheme = "Purple" elseif customVar.pinkThemeSelected then customVar.selectedTheme = "Pink" end local highestLevel = thisRate:retrieve( "highestLevel" ) if highestLevel == nil then highestLevel = 1 end composer.notificationOn = thisRate:retrieve( "notificationOn" ) if composer.notificationOn == nil then composer.notificationOn = false end customVar.numGames = thisRate:retrieve( "numGames" ) if customVar.numGames == nil then customVar.numGames = 0 end highScore = thisRate:retrieve( "highScore" ) if highScore == nil then highScore = 0 end lifeTimeBlocks = thisRate:retrieve( "lifeTimeBlocks" ) if lifeTimeBlocks == nil then lifeTimeBlocks = 0 end composer.showStartOptions = thisRate:retrieve( "showStartOptions" ) if composer.showStartOptions == nil then composer.showStartOptions = true end composer.switchState = thisRate:retrieve( "switchState" ) if composer.switchState == nil then composer.switchState = false end composer.comma = function(amount) local formatted = tostring(amount) while true do formatted, k = string.gsub(formatted, "^(-?%d+)(%d%d%d)", '%1,%2') if (k==0) then break end end return formatted end local function switchOn() composer.showStartOptions = false thisRate:store( "showStartOptions",composer.showStartOptions ) composer.switchState = true thisRate:store( "switchState",composer.switchState ) thisRate:save() end local function switchOff() composer.showStartOptions = true thisRate:store( "showStartOptions",composer.showStartOptions ) composer.switchState = false thisRate:store( "switchState",composer.switchState ) thisRate:save() end composer.toggleStartOptions = function( event ) local switch = event.target if switch.isOn then switch:setState( { isOn=true, isAnimated=true, onComplete=switchOff } ) print(switch.isOn) else switch:setState( { isOn=false, isAnimated=true, onComplete=switchOn } ) print(switch.isOn) end end composer.localNotify = function() if composer.notificationOn then system.cancelNotification( ) composer.notificationOn = false thisRate:store("notificationOn",composer.notificationOn) thisRate:save() end local futureTime = 0 local randMessageNum = math.random(1,4 ) local badgeNum = 0 local runNotify = function() if randMessageNum \< 4 then randMessageNum = randMessageNum + 1 else randMessageNum = 1 end local randMessage futureTime = futureTime + (5 \* 24 \* 60 \* 60 ) -- 5 Days composer.notificationOn = true thisRate:store("notificationOn",composer.notificationOn) thisRate:save() customVar.numGames = thisRate:retrieve( "numGames" ) if customVar.numGames == nil then customVar.numGames = 0 end highScore = thisRate:retrieve( "highScore" ) if highScore == nil then highScore = 0 end lifeTimeBlocks = thisRate:retrieve( "lifeTimeBlocks" ) if lifeTimeBlocks == nil then lifeTimeBlocks = 0 end if customVar.numGames \> 0 then if randMessageNum == 1 then randMessage = "Play Jump Game again to see if you can beat your high score of "..composer.comma(highScore) elseif randMessageNum == 2 then randMessage = "The Jump Game blocks are getting lonely... You've jumped on "..composer.comma(lifeTimeBlocks).." of them already but they want more!" elseif randMessageNum == 3 then randMessage = "You've played "..composer.comma(customVar.numGames).." games of Jump Game. Time for one more?" elseif randMessageNum == 4 then if highestLevel == 1 then randMessage = "You haven't made it passed level 1 on Jump Game yet. Play now and get to the elevator blocks on level 2!" else randMessage = "You've made it to level "..highestLevel.." on Jump Game. Play now and see if you can get to level "..(highestLevel+1).."!" end end else if randMessageNum == 1 or randMessageNum == 3 then randMessage = "The Jump Game blocks are offended that you haven't finished a game yet. Come jump on them to make them feel better!" elseif randMessageNum == 2 or randMessageNum == 4 then randMessage = "You haven't made it passed level 1 on Jump Game yet. Play now and get to the elevator blocks on level 2!" end end if ( system.getInfo( "platformName" ) == "iPhone OS" ) then badgeNum = badgeNum +1 local options = { alert = randMessage, badge = badgeNum, sound = "alarm.caf", custom = { msg = "Alarm" } } local notificationID = system.scheduleNotification( futureTime, options ) else local options = { alert = randMessage, sound = "alarm.caf", custom = { msg = "Alarm" } } local notificationID = system.scheduleNotification( futureTime, options ) end end composer.timerStash.timer027 = timer.performWithDelay( 100, runNotify ) composer.timerStash.timer027 = timer.performWithDelay( 100, runNotify ) composer.timerStash.timer027 = timer.performWithDelay( 100, runNotify ) composer.timerStash.timer027 = timer.performWithDelay( 100, runNotify ) return true end noAdsAdGroup = display.newGroup( ) mainGroup:insert( noAdsAdGroup ) local function onRemoveAdsAd(event) if "clicked" == event.action then local i = event.index if 1 == i then analytics.logEvent( "Clicked NoAdsAd Banner, Yes" ) if store.isActive then if store.canMakePurchases then composer.showLoading() if ( store.availableStores.apple ) then store.purchase( {"01removeAds"} ) elseif ( store.availableStores.google ) then store.purchase( "01removeAds" ) end else local alert = native.showAlert( "Jump Game","In-app purchases are disabled in your device settings. Please enable and try again from the Jump Game menu settings.", { "Ok" }, addListeners ) return true end else local alert = native.showAlert( "Jump Game","You are not connected to the App Store. Please check your internet connection and try again from the Jump Game menu settings.", { "Ok" }, addListeners ) return true end elseif 2 == i then analytics.logEvent( "Clicked NoAdsAd Banner, No" ) return true end end end local function removeAdsAd(event) analytics.logEvent( "Clicked NoAdsAd Banner" ) local alert = native.showAlert( "Jump Game","Do you want remove all ads from Jump Game?", { "Yes Please!", "No thanks", }, onRemoveAdsAd ) return true end local function onNoAdsAdEvent(self) if composer.currScene ~= "game" then removeAdsAd() end end adPlaceholder = display.newRect( 0, display.contentHeight-100, display.contentWidth, 100 ) adPlaceholder:setFillColor( 0.1,0.1,0.1 ) adPlaceholder.anchorX = 0 adPlaceholder.anchorY = 0 adPlaceholder.alpha = 1 noAdsAdGroup:insert(adPlaceholder) noAdsAd = widget.newButton { id = "noAdsAd", defaultFile = "noAds.png", overFile = "noAdsOver.png", width = 640, height = 100, onRelease = onNoAdsAdEvent, } noAdsAd.x = display.contentWidth/2; noAdsAd.y = display.contentHeight-48 noAdsAd.name = "noAdsAd" noAdsAdGroup:insert(noAdsAd) noAdsAdGroup.alpha = 0 local function adListener4( event ) if ( event.isError ) and composer.removeAdsIAP == false then analytics.logEvent( "AdMob Error, Switching to NoAdsAd Banner" ) print("Switch to NoAdAd") noAdsAdGroup.alpha = 1 else analytics.logEvent( "Showing AdMob Banner" ) end return true end ads.init( "admob", "################" , adListener4 ) local function adListener2( event ) if ( event.isError ) and composer.removeAdsIAP == false then --composer.currScene ~= "game" and if composer.currScene ~= "game" then analytics.logEvent( "iAd Error, Switching to Admob Banner" ) --ads.hide() print("Switch to admob") ads:setCurrentProvider( "admob" ) ads.show( "banner", { x=0, y=display.contentHeight-50, appId="####################", testMode=false } ) else analytics.logEvent( "iAd Error, Switching to NoAdsAd Banner" ) noAdsAdGroup.alpha = 1 end else analytics.logEvent( "Showing iAd Banner" ) end return true end ads.init( "iads", "###########", adListener2 ) local function adListener( event ) if ( event.type == "adStart" and event.isError ) and composer.removeAdsIAP == false then analytics.logEvent( "Vungle Error, No Ad Served" ) elseif ( event.type == "adEnd" ) then analytics.logEvent( "Showing Vungle Fullscreen" ) customVar.time2 = 0 thisRate:store("time2",customVar.time2); thisRate:save(); end return true end ads.init( "vungle", "#############", adListener ) composer.showAd = function() if composer.removeAdsIAP == false then noAdsAdGroup.alpha = 0 ads.hide() ads:setCurrentProvider( "vungle" ) ads.show( "interstitial" ) else return true end end composer.showAd4 = function() if composer.removeAdsIAP == false then noAdsAdGroup.alpha = 0 ads.hide() ads:setCurrentProvider( "admob" ) ads.show( "banner", { x=0, y=display.contentHeight-50, appId="##################", testMode=false } ) else return true end end composer.showAd2 = function() if composer.removeAdsIAP == false then noAdsAdGroup.alpha = 0 ads.hide() ads:setCurrentProvider( "iads" ) ads.show( "banner", { x=0, y=display.contentHeight-50 } ) else return true end end composer.hideAd = function() ads.hide() noAdsAdGroup.alpha = 0 end composer.loadAd = function() ads.load( "interstitial", { appId="################", testMode=false } ) end composer.isAdLoaded = function() ads.isLoaded("interstitial") end -- function to listen for system events local function onSystemEvent( event ) if event.type == "applicationStart" then if ( system.getInfo( "platformName" ) == "iPhone OS" ) then gameNetwork.init( "gamecenter" native.setProperty( "applicationIconBadgeNumber", 0 ) end composer.localNotify() if composer.removeAdsIAP == false then if ( system.getInfo( "platformName" ) == "Android" ) then composer.showAd4() elseif ( system.getInfo( "platformName" ) == "iPhone OS" ) then composer.showAd2() end end return true elseif event.type == "applicationResume" then composer.localNotify() if composer.removeAdsIAP == false then if ( system.getInfo( "platformName" ) == "Android" ) then composer.showAd4() elseif ( system.getInfo( "platformName" ) == "iPhone OS" ) then composer.showAd2() end end return true end end Runtime:addEventListener( "system", onSystemEvent ) local function myUnhandledErrorListener( event ) analytics.logEvent( "Unhandled Error", { errorMessage=event.errorMessage, stackTrace=event.stackTrace } ) end Runtime:addEventListener("unhandledError", myUnhandledErrorListener) local spinner local loadingOverlay local function loadingOverlayEvent(event) return true end loadingOverlay = display.newRect( display.contentWidth/2, display.contentHeight/2, display.contentWidth, display.contentHeight ) loadingOverlay.alpha = 0 loadingOverlay:setFillColor(0,0,0) mainGroup:insert(loadingOverlay) local options = { width = 128, height = 128, numFrames = 1, sheetContentWidth = 128, sheetContentHeight = 128 } local spinnerSingleSheet = graphics.newImageSheet( "loading.png", options ) -- Create the widget spinner = widget.newSpinner { width = 112, height = 112, sheet = spinnerSingleSheet, startFrame = 1, deltaAngle = 10, incrementEvery = 20 } spinner.alpha = 0 spinner.x = display.contentWidth/2 spinner.y = display.contentHeight/2 composer.showLoading = function() display.getCurrentStage():setFocus( loadingOverlay ) loadingOverlay:addEventListener( "touch", loadingOverlayEvent ) transition.to (loadingOverlay, {time=500, alpha=0.6} ) transition.to (spinner, {time=500, alpha=1} ) spinner:start() end composer.endLoading = function() transition.to (loadingOverlay, {time=500, alpha=0} ) transition.to (spinner, {time=500, alpha=0} ) spinner:stop() loadingOverlay:removeEventListener( "touch", loadingOverlayEvent ) display.getCurrentStage():setFocus( nil ) end isDebug = true local options = { effect = "fade", time = 500, } composer.gotoScene("menu", options) return true end composer.timerStash = {} composer.trans = {} composer.gt = {} composer.cancelAllTimers = function() local k, v for k,v in pairs(composer.timerStash) do timer.cancel( v ) v = nil; k = nil end composer.timerStash = nil composer.timerStash = {} end composer.pauseAllTimers = function() local k, v for k,v in pairs(composer.timerStash) do timer.pause( v ) end end composer.resumeAllTimers = function() local k, v for k,v in pairs(composer.timerStash) do timer.resume( v ) end end -- composer.pauseAllTransitions = function() local k, v for k,v in pairs(composer.trans) do transition.pause( v ) end end composer.cancelAllTransitions = function() local k, v for k,v in pairs(composer.trans) do transition.cancel( v ) v = nil; k = nil end composer.trans = nil composer.trans = {} end --cancel all gtweens composer.cancelAllTweens = function() local k, v for k,v in pairs(composer.gt) do v:pause(); v = nil; k = nil end composer.gt = nil composer.gt = {} end main()

Main File:

display.setStatusBar(display.HiddenStatusBar) local composer = require( “composer”) if “Android” == system.getInfo( “platformName” ) then return true else …

And I’m gonna stop you right there O_o

On the off chance that you’re still puzzled (I hope not). You are executing this in immediate mode i.e. as soon as the app starts. Basically you are saying if android return true and do nothing. This is why you have a blank screen!

Thats not it unfortunately.  I had already tried building with that section commented out and it didn’t work.  I have just tried it commented out again and adjusting it to only run that code if on iOS, still no luck.  Any other ideas?

Main File:

display.setStatusBar(display.HiddenStatusBar) local composer = require( “composer”) if “Android” == system.getInfo( “platformName” ) then return true else …

And I’m gonna stop you right there O_o

On the off chance that you’re still puzzled (I hope not). You are executing this in immediate mode i.e. as soon as the app starts. Basically you are saying if android return true and do nothing. This is why you have a blank screen!

Thats not it unfortunately.  I had already tried building with that section commented out and it didn’t work.  I have just tried it commented out again and adjusting it to only run that code if on iOS, still no luck.  Any other ideas?