Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Inconsistent behavior of getAppHomePath() #2551

Closed
jsfan3 opened this issue Sep 19, 2018 · 8 comments
Closed

Inconsistent behavior of getAppHomePath() #2551

jsfan3 opened this issue Sep 19, 2018 · 8 comments
Assignees
Milestone

Comments

@jsfan3
Copy link
Contributor

jsfan3 commented Sep 19, 2018

Hi,
do you remember the unsolved bug #2486? The problem was that on iPhone X the images stored inside the app are lost after every app upgrade (while on Android this bug is absent).

After one month and half, I found the cause of the bug and the solution. The cause is not the zero length file size of the images as we supposed... there is a completely different reason for which all my app images are lost after every app upgrade.

The problem is this line:
String pathAvatar = getAppHomePath() + System.currentTimeMillis() + ".jpg";
because getAppHomePath() returns a different value after an app upgrade (on iPhone X), with the result that the previously saved images become unaccessible.

To be sure that my hypothesis is correct, I wrote this three-lines test case:

Form hi = new Form("AppHomePath", BoxLayout.y());
hi.add(new SpanLabel("FileSystemStorage test - The AppHomePath is:\n\n" + FileSystemStorage.getInstance().getAppHomePath()));
hi.show();

At the first app execution, I got that the AppHomePath is:
file:///var/mobile/Containers/Data/Application/FFB4ED3C-A6B1-46E8-B7F1-966EAD62C5C6/Documents//

After reinstalling the same test-case app (WITHOUT uninstall it before, so it's like an upgrade), I got that the AppHomePath is:
file:///var/mobile/Containers/Data/Application/A5DC9A5A-D6FB-4B7E-BC70-37C9C3613C84/Documents//

After discovering this issue, the solution of the bug was obvious: I replaced the use of FileSystemStorage with the use of Storage to save the images, and now my app can access its images after any upgrade.

HOWEVER, is this unexpected behaviour of getAppHomePath() a bug or not? And is it documented?

Thank you for your support

@codenameone codenameone deleted a comment from sian0 Sep 19, 2018
@codenameone
Copy link
Collaborator

Odd. Storage and app home should be identical on iOS.
What's the path the 3 root folders in file system storage? I'm asking because this is the code that implements this:

        if(Display.getInstance().getProperty("iosNewStorage", "false").equals("true")) {
            roots = new String[] {
                    nativeInstance.getDocumentsDir(),
                    nativeInstance.getCachesDir(),
                    nativeInstance.getResourcesDir()
                };
        } else {
            roots = new String[] {
                    nativeInstance.getCachesDir(),
                    nativeInstance.getDocumentsDir(),
                    nativeInstance.getResourcesDir()
                };
        }

iosNewStorage should be defined to true for all modern builds so it's back to the original concern.

@jsfan3
Copy link
Contributor Author

jsfan3 commented Sep 21, 2018

I'm sorry, I didn't understood what I have to do to give you the information you asked: how can I modify the test case that I provided you to get the three dirs that you want to know?

@codenameone
Copy link
Collaborator

I was referring to the output of:

        for(String s : FileSystemStorage.getInstance().getRoots()) {
            Log.p(s);
        }

@jsfan3
Copy link
Contributor Author

jsfan3 commented Sep 21, 2018

Ok. I modified the code so:

Form hi = new Form("AppHomePath", BoxLayout.y());
        hi.add(new SpanLabel("FileSystemStorage test - The AppHomePath is:\n\n" + FileSystemStorage.getInstance().getAppHomePath()));
        for(String s : FileSystemStorage.getInstance().getRoots()) {
            hi.add(new SpanLabel(s + "\n\n"));
        }
        hi.show();

Screenshot of first execution after app installation on iPhoneX:
firstrun

Screenshot of first execution after app re-installation (without uninstalling it, so it's like an upgrade):
secondrun

@codenameone
Copy link
Collaborator

OK I see the problem. It's related to this https://developer.apple.com/library/archive/technotes/tn2285/_index.html

Specifically:

When an app is updated, the .app bundle is completely replaced by the latest version of the app. Also, the absolute path to the app's container ("Application_Home") and thus all files inside it, will change. For this reason, you must only save paths to files relative to your application container.

In other words you can't store full paths to files and expect them to work across executions in iOS...

That kind of sucks.

I have two ideas for the fix although both aren't ideal...

Approach 1

We can add a virtual file path to iOS that will match file://home internally this will map to the documents folder seamlessly. This in itself should be pretty easy to implement but returning that from getAppHomePath() could be problematic in terms of compatibility. We should probably enable it dynamically with a display preference or build hint.

The advantage of this approach is that it's the "right thing". But it requires user intervention.

Approach 2

We can detect and "fix" bad file URI's "seamlessly". When passed a file URL we can check if the URL is a documents URL e.g. something like this:

if(url.startsWith("file:///var/mobile/Containers/Data/Application") && url.indexOf("/Documents/") > -1) {
     // check that the random string in the middle matches the existing app home URL if not fix it
} 

This approach is seamless but relies on some implementation details. It might lead us down a rabbit hole of pain.

@shannah what do you think?

@shannah
Copy link
Collaborator

shannah commented Sep 24, 2018

I think we should implement both approaches. For most cases, approach 1 will work fine, but approach 2 will be necessary to catch things that slip through the cracks

@codenameone
Copy link
Collaborator

Including changing getAppHomePath()?

That might break production apps because we'd need to review every piece of code that accesses the filesystem and fix it. We might also break code that uses native code to access this.

@shannah
Copy link
Collaborator

shannah commented Sep 24, 2018

Good point.

@codenameone codenameone removed their assignment Jul 8, 2020
shannah added a commit that referenced this issue Mar 4, 2021
…p is updated the container root changes. In most places the file paths are fixed seamlessly, but createMedia() uses a different mechanism for fixing paths and it wasn't updating paths after an app update.

Reference: #2551 The original issue when app root was reported as changed on app updates.
Fixes #3362
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants