Hi Studycat & dchan;
So sorry that I have been out of the loop for more than a day. Some important things came up on the personal side of life and I am away from work as a result. Plan to be back at it tomorrow to test further.
Steve
Hi Studycat & dchan;
So sorry that I have been out of the loop for more than a day. Some important things came up on the personal side of life and I am away from work as a result. Plan to be back at it tomorrow to test further.
Steve
Steve
No problem, I am just glad I am not the only one who has had this kind of problem.
Hi dchan, Studycat and Alex;
OK, I finally had the time to buckle down and test the things suggested. First off, dchan was correct with his suggestion of setting “cached_displayNewGroup” to a global. But spooky oddnesses surrounding “widget.lua” and how it does very interesting thing in different situations completely threw me and kept me a step away from properly implementing dchan’s suggested methodology when I tried it (nearly a week ago). I’m still not certain that I don’t have to do one last thing to make it all work in all instances – but I’ll get to that question a bit further down.
I have a bunch of observations on this and I will probably break this into separate posts – just so it all stays understandable.
WHAT ACTUALLY WORKS
Place “widget.lua” in the main project directory next to “main.lua” and don’t worry that things are screwy if you ever try to actually instantiate it in the simulator (see below) in order to test in that environment.
In the “widget.lua” file, change the “local” variable for cached_displayNewGroup to a global. Here’s my code and I include my print statements because stuff I will write in a bit will make more sense if you see them:
<snip>
local widget =
{
version = “2.0”,
_directoryPath = “widgetLibrary.”,
}
print ("########### WIDGET NEXT TO MAIN TRACE POS #1")
– STEVE MODIFIED THIS IN ORDER TO RE-ESTABLISH THIS FUNCTION AFTER THE WIDGET SCRIPT HAS MESSED IT UP
– This cached_displayNewGroup was a “local”, but Steve made it a global
cached_displayNewGroup = display.newGroup
print ("########### WIDGET NEXT TO MAIN cached_displayNewGroup set to global")
print ("########### WIDGET NEXT TO MAIN TRACE POS #2")
function display.newGroup()
local newGroup = cached_displayNewGroup()
<snip>
Place the secondary widget files and the folder “widgetLibrary” (and contents) in the project as well. As I have no idea which of these files might be called or used (by Corona’s code) if the Google Play Expansion file still needs to be loaded, I placed them all there.
Make certain that the “widgetLibrary” does not still contain a “widget.lua” file – this file should only exist on the same level as “main.lua”.
====== CONTINUED BELOW ========================================================================
WHY I HAD THOUGHT THIS DIDN’T WORK (previously)
Remember my comment at the beginning of the week that my print statements weren’t outputting with logcat?
I had actually tried two things to test the globalizing of cached_displayNewGroup and both failed in my test/
FIRST THING TRIED
THIS FAILS IN THE SIMULATOR:
Place “widget.lua” in the main project directory next to “main.lua” with the variable set to be global.
Place this code in “main.lua” to test it all in the simulator:
widget = require(“widget”)
if (cached_displayNewGroup) then
print ("########### MAIN (widget.lua next to main) - cached_displayNewGroup is NOT nil")
function display.newGroup()
return cached_displayNewGroup()
end
else
print ("########### MAIN (widget.lua next to main) - cached_displayNewGroup IS NIL")
end
When I run this, NONE of the print statements in “widget.lua” (see previous post) actually display (as widget is birthed) and cached_displayNewGroup is nil when I test for it.
But, on the other hand, I know that the code in “widget.lua” actually did run (or the Widget code ran somewhere else) – it managed to hose the removeSelf() functionality of any dispely groups I tried to subsequently remove.
After this essentially failed in the simulator, I didn’t think to try it fully on a build for the device (I should have)
=============================================================================
And another bit of simulator “voodoo”. If I change the name of the lua file
to “widget1.lua” and instantiate with this:
widget = require(“widget1”)
Then everything runs just fine with all print statements firing and
cached_displayNewGroup is NOT nil!
I think I know what you are doing here, I just think it is strange that you
don’t document it anywhere. It will waste someone else’s hours down the road.
=============================================================================
====== CONTINUED BELOW ========================================================================
SECOND THING TRIED
Since I had that strange experience on the simulator, I decided to try everything by using a “widget.lua” file in the “widgetLibrary” folder (the default placement in your examples). When I simply did this and changed my widget=t birth to this:
widget = require(“widgetLibrary.widget”)
The result was that everything tested out well in the simulator and on a device (no expansion file yet, just a single APK). With these results under my belt, I optimistically made a Google Play Build and placed it in the store (with expansion file). Of course I commented out my own birthing of “widget” – I expected that the “Corona Stub” would do that.
I don’t know why I was optimistic. My print statements never fired and, apparently, the Corona Stub didn’t use my instance of “widget.lua” in the directory. So that is where I ended up earlier this week.
BUT THERE’S MORE INTERESTING STUFF (below)
====== CONTINUED BELOW ========================================================================
INTERESTING STUFF
Did you know . . . .
** That if you place a “widget.lua” file next to the “main.lua” file and you also place another copy of the “widget.lua” file in a “widgetLibrary” folder, BOTH FILES will be fired by the “Corona Stub” that handles the expansion file checking. The trace statements in each of them will run (file next to “main.lua” runs first). But after they each run, the app stops at a full black screen and nothing else happens (and there are no errors or anything outputted to explain the problem). What is fascinating here is that the “widget.lua” file in a “widgetLibrary” folder DOES NOT RUN when it is there all by itself (without a twin next to “main.lua”).
FINAL IMPORTANT CONCERN
The one thing that concerns me in the approach that I “think” is successful is that I get the following output on first run of the App after it is now downloaded from the Google Play Store. It is this:
> Class.forName: widgetLibrary.widget.luaLoader
WARNING: Could not load ‘LuaLoader’
> Class.forName: widgetLibrary.widget.luaLoader
WARNING: Could not load ‘LuaLoader’
What scares me here is whether this means that “if the APK portion of the app actually needed to go and download the “.obb” expansion file”, that things would break. I just don’t know and would love advice on what is triggering this and whether there is another LUA file I need to place in my project. I would appreciate advice.
Thanks;
Steve
Steve
It’ll take me a while to read through all that slowly and see if it matches what I see.
Would you be able to make a concise example app? What I did was made an example app
by cut 'n pasting bits from our real app until I found what wasn’t working. If you had an example bit of code I’d be happy to run it here and see if I can get the same results as you. It would also be easier for the Corona guys if they had something that reproduced the results and they could debug better.
Hi Studycat;
Thanks for the question. And thanks so much for your thoughts on approaches to the problem. I’m presently under the gun to complete a Flash game that I promised would be complete by late this week (yes, my web development roots are on the dark side and we still make money on this Flash stuff). So I’m not certain when I can get to it.
If you are simply interested in what worked for us, it is described in the 4 points of my first post on 8/23.
And if anyone has any questions about “why does this happen?”, it stems from the fact that the core widget code creates a replacement global display.newGroup() function that contains an altered removeSelf(). This removeSelf() is incompatible with the normal functioning of display groups and removing them when cleaning up properly.
And in the specific instance of a “Corona Stub” (that deals with an expansion file), the actual instance of “widget” is destroyed by the stub before the developer’s “main.lua” is run – but the corrupting global display.newGroup() function is left in place by the stub.
In the short, short run, the kludgy steps above eliminate my immediate problem.
In the less short run, Corona could fix this “Corona Stub” problem by reverting display.newGroup() to its intended functioning at the time when the stub has finished its work and is about to set the widget instance to nil.
And by far the best, most elegant solution would be for someone at Corona to write a better memory cleanup chunk of code in “widget.lua”; a chunk of code that does not supplant normal, documented Corona functionality in certain instances – with those instances producing the errors that we developers have experienced.
Does that make sense?
Thanks again for everyone’s help!
Steve
Hi Studycat (and Corona foilks);
I hope that you are getting messages on this topic so that you will see this post.
We have the exact same problem that you first posted about on April 17th – but we are experiencing this with two NEWER BUILDS (builds that should no longer have a problem). Any guidance or suggestions you can provide would be great (or from Corona). Here are the details:
A) When we build an APK (65 Mb) without using an Expansion File and install it on devices via ADB, our app runs fine on first run and forever thereafter.
B) So, we then build it with an expansion file and place the app in the Google Play store. When we and other users then download/install it from there, the app starts up just fine and gets to a “landing” screen. But as soon as users try to exit that landing screen and go to another screen (via a Director transition), we get an error that is nearly identical to what you posted at the top of this thread. It is:
I/Corona (19966): Runtime error
I/Corona (19966): stack traceback:
I/Corona (19966): [C]: ?
I/Corona (19966): ?: in function ‘remove’
I/Corona (19966): ?: in function ‘removeSelf’
I/Corona (19966): ?: in function ‘remove’
I/Corona (19966): ?: in function ‘clean’
I/Corona (19966): ?: in function ‘?’
I/Corona (19966): ?: in function ‘_listener’
I/Corona (19966): ?: in function <?:141>
I/Corona (19966): ?: in function <?:218>
I/Corona (19966): Runtime error
I/Corona (19966):
I/Corona (19966): stack traceback:
I/Corona (19966): [C]: ?
I/Corona (19966): ?: in function ‘remove’
I/Corona (19966): ?: in function ‘removeSelf’
I/Corona (19966): ?: in function ‘remove’
I/Corona (19966): ?: in function ‘clean’
I/Corona (19966): ?: in function ‘?’
I/Corona (19966): ?: in function ‘_listener’
I/Corona (19966): ?: in function <?:141>
I/Corona (19966): ?: in function <?:218>
I noticed you had “cleanGroups” in your error output. But your experience and mine are spookily the same.
C) The game freezes when I get the above error. But if I exit the game entirely and start it back up, the game runs fine on its second play and every time thereafter (with no error message or any other weirdness). This experience has been duplicated on a number of devices.
So to quickly summarize:
– APKs built with Version 1150 and 1185 perform exactly alike.
– Run the game in the simulator and it produces no error - ever.
– Build a single large APK file and install on devices and it produces no error - ever.
– Build for Google Play with Expansion file and install game from there and the game reproducibly delivers the above error on first launch.
– But that same app (using expansion file) that was installed from Google Play never produces this error on second launch or thereafter.
So any insight which you or Corona folks can provide would be most timely as this is a live App (and a popular one) and I need to fix soonest.
Steve Bullock
Adveractive
Hi,
Are you using widgets in your app?
Hi sbullock
If I recall correctly I think we eventually found that in some cases overriding corona sdk functions had something to do with it.
We were overriding the display.newGroup function and the remove and removeSelf functions.
This is the code that was breaking our project:
[lua]
local oldNewGroup = display.newGroup
display.newGroup = function( … )
local group = oldNewGroup( … )
local oldRemoveSelf = group.removeSelf
group.removeSelf = function( self )
if self.numChildren then
for i = self.numChildren, 1, -1 do
self[i]:removeSelf()
end
end
oldRemoveSelf( self )
end
group.remove = function( self, o )
if type( o ) == ‘number’ then
self[o]:removeSelf()
else
print “group.remove removeSelf”
o:removeSelf()
end
end
return group
end
[/lua]
We had a source file “cleangroup.lua” which I strongly suspect was pulled off the internet somewhere to deal with clean up issues that are a non-issue now. Once we stopped overriding display.newGroup it worked for us.
Later we had a response on bug report, Corona told us they though it could be because widget’s and our code were both overriding the display.newGroup function. That explanation fitted very well.
I hope this helps.
Hi Studycat and dchan;
Thanks for your thoughts. We are not using widgets.
And to our knowledge, none of our code or functions are overriding any standard Corona functions.
We use a “clean” function in our screen scripts. This “clean” function is called by director.lua from director’s “callClean” function – when transitioning from screen to screen. Studycat’s post has me wondering if SOMETHING is triggering an extra call to one of these functions.
What I don’t understand is why this is entirely a “first run when there is an expansion file present” problem. I realize that there is some Corona code running this first time to link the two files together properly – but why should that code be impacting a specific code execution of mine that runs reliably in all other instances (note – same App with same code has been released on iOS and on Nook/Android).
Dchan – can you advise if the Corona code for handling of expansion files might have any functions named “clean”, “callClean” or “cleanGroups” that isn’t being cleaned up after it runs . . . or anything similar? Or if you have any other thoughts, it would be very welcome.
A big part of my problem is that I haven’t quite figured out is how to do the “expansion file” thing using adb on a local device. So I am essentially stuck with posting builds to a live app (fyi, the Google Play “beta” feature they added doesn’t let you test a beta install properly if the App i already live – it is really poorly done).
Thanks for any more thoughts you might offer.
Steve
Can you add a require(“widget”) to the top of your code and then run it in the simulator and see if the problem occurs? I believe the issue isn’t really with expansion files but widgets. The widget library overrides certain functions such as display.newGroup(). If you try to override those functions and do a recursive call it will cause unexpected behavior.
This happens the first time with expansion files is because the first time the application is run, we need to check Google’s licensing server to make sure we have the correct expansion file. When we do that we’re requiring the widget library in case we need to display the downloading screen.
Hi dchan;
That’s exactly the problem. So happy that you have identified it.
So, in essence, the Widget library destroys the normal functionality of a group (created with display.newGroup()). That’s interesting.
Do you have any sample code that can restore the “normal” functionality and remove the widget-induced error? I’m sure hoping so :-).
Thanks for being so prompt in getting me your advice.
Steve
Hi,
One possible option is to include the widget library inside your own project and then remove the override of display.newGroup(). You can find the library here: https://github.com/coronalabs/framework-widgets. Thats the only work around we have right now but we’ll see if we can find something better.
Hi dchan;
Thanks. A couple of questions:
– I am a Pro Subscriber (not Enterprise). Is the Widget Library something that I can include by simply placing “it” (a .lua file, a directory, etc.) in my main folder?
– When I do a build requiring the expansion file, your build software will know to not overwrite “my widget” with the “normal widget” library. Correct?
– And the url you are providing above for the widget library returns a 404 error :-).
Thanks;
Steve
Yes that would be how you do it
Yes thats how it should be
Thanks dchan.
I’ll let you know what happens. Also, I’m assuming that my removing the override on display.newGroup won’t bust/break the ability of the app to diplay the widgets if it does need to complete the download of the expansion file. Appreciate your guidance.
Steve
What I think you should actually do is to modify
https://github.com/coronalabs/framework-widgets/blob/master/widgetLibrary/widget.lua#L44
and remove the local keyword from that line. Once you remove that it will become a global variable. Once your main starts you can then do something like
function display.newGroup()
return cached_displayNewGroup()
end
which should restore display.newGroup() to its old functionality. This way if the expansion files do need to be downloaded, the widgets are unmodified. Its only when you get to your main.lua, which means expansion files are downloaded, that you break widgets.
Hi dchan;
Thanks. I spent my Saturday working on this. The result was utter failure.
For purposes of this discussion, I’ll call the Corona code which does all of the handling of the expansion file (linking of APK to Expansion, downloading of Expansion, etc.) the “Corona Stub”. After testing various things locally and then posting a pair of builds to Google Play, this is my analysis:
a) The “Corona Stub” runs before anything in my “main.lua” runs (had thought this would be the case).
b) During the build process, the “Corona Stub” probably loads its own version of widget.lua without regard to whether the developer is using (and loading) a widget.lua file of his own. As you described, the “Stub” may need to take over the downloading of the expansion file – so it always instantiates its own widget.lua the very first time an app is run.
c) Any widget.lua file placed in my own project files is entirely ignored and not used by the “Stub”. So making any changes within my widget.lua code has no impact on the problem. Any print statements in MY widget.lua file are never triggered. The change of the local “cached_displayNewGroup” to a global doesn’t happen – so I cannot reverse it.
d) Hence, the impact of a problematic piece of code written in widget.lua (where a core display function was hijacked so that it breaks the removeSelf() best recommended memory practice) has now created a problem in another piece of Corona functionality – the competent handling of expansion files.
e) In essence, I cannot restore display.newGroup() to its intended original and documented functionality. But you Corona folks could . . . if the “stub” code had about 5 lines of proper cleanup code of its own running. The “stub” would do the cleanup once it knows that it has no more work to do. At that point, it could easily restore display.newGroup() and then it could set the entire “widget” to nil. This would effectively give developers back the “clean start” that they expect to have when their first line of “main.lua” runs.
So, I am totally open to thoughts and anything that will actually work. I do feel strong urgency on this. The game of ours that has the problem is “Just 2 Words” – your company’s choice as _ Corona App of the Month _ for July. The App has had about 150,000 downloads in last month on iOS – but only 1,500 in Google Play. It was an Apple New & Notable which really pushed its numbers on Apple. We have some advertising and promotion on the Android side this month – and we are handling e-mails daily asking “what gives, the game won’t run the first time.”
So far, we haven’t had a bunch of bomb reviews on this problem – but you never know when this might happen. As expansion files are a Google Play thing, this is not a hindrance to the App becoming a long running hit everywhere else. But it is certainly going to appear to be lame/broken if acquired through Google Play - until we can figure something out.
Thanks!
Steve