Use of Resources folder

  1. 4 weeks ago

    Dan P

    Apr 18 Farmington, NM or Las Vegas, N...

    My project was started over 15 years ago in REALbasic by a consultant, and he did not use a Resources folder. Perhaps that early IDE didn't use one. Anyway, my app is now having a problem finding its data folders on some Macs when the parent folder and its contents have been zipped and expanded.

    I am currently using Xojo 2016r4.1. Everything is in the parent folder OpVP. It contains, along with other data files, OptimumVP.app and a folder "RequiredFiles" containing several text files. My code looks for that folder as follows:

    dim f as FolderItem
    f = GetFolderItem( "RequiredFiles" )
    if not f.directory then ...[error code]

    This works fine except on some Mac systems (especially Mojave) when the parent folder and its contents have been zipped (to be sent by email) and expanded. In that case, f.directory is nil.

    Questions:

    1. Should I create a Resources folder?
    2. Should it be next to the app in the OpVP folder?
    3. Should all the data files be in the Resources folder?
    4. Is there anything (other than the app) that should not be in the Resources folder?
    5. What should the code be to locate a folder within the Resources folder?
    6. What should the code be to open a data file within that folder?
    7. Is all this the same for both Windows and Mac?

    Thanks,
    Dan

  2. Tim P

    Apr 18 Pre-Release Testers Rochester, NY
    Edited 4 weeks ago
    1. Yes
    2. Inside the app, use a CopyFiles step
    3. Yes, copy them into your own subfolder of Application Support on first launch. You can use TPSF to help with that.
    4. -
    5. TPSF.Resources or SpecialFolder.Resources depending on your Xojo version
    6. Same as any other code, just get the item from the resources.
    7. It can be if done correctly

    I'm not sure you're entirely grasping the idea, the Resources folder gets bundled inside OptimumVP.app, so your question number four I did not understand.

    OptimimumVP.app
      Contents
        Frameworks
        Info.plist
        MacOS
        Resources

    That resources folder in there is where all app files should be bundled. If you need to write back into them, you need to copy them out of the app on your first launch. If it's read only, then you should be fine to work with them in there - except for SQLite. Xojo can't open SQLite read only.

    I hope this helped clear some things up. I'm sure I left some things out so if you have more questions please ask! I'm happy to help people package their Mac apps correctly.

  3. Dan P

    Apr 18 Farmington, NM or Las Vegas, N...

    Thank you, Tim, for your quick response. I've been programming computers for over 50 years, but prior to this project it was all in machine/assembler code so I had complete control over everything. The object-oriented IDE is great, but there are many things going on below the surface that I don't understand.

    So you're absolutely right that I'm not grasping the idea. Are you saying that the app must create the Resources folder at run time start up? And then it copies the sub-folders into that folder? I guess I'm entirely lost. Is there example code somewhere?

    I'm not using SQLite at all. The app never writes into the files in the RequiredFiles folder, but there are other folders containing text files that are read and written by the app.

    I was hoping that some simple solution like
    f = GetFolderItem.parent.child( "RequiredFiles" )
    would work. No?

    The code I showed in my first post has been working fine for 25 years, and fails only when the package is compressed and then expanded on a different computer. Something is not restored when the package is expanded.

  4. Norman P

    Apr 18 Pre-Release Testers, Xojo Pro Freeport, Bahamas

    @Dan P So you're absolutely right that I'm not grasping the idea. Are you saying that the app must create the Resources folder at run time start up?

    No
    For macOS this is how an app is normally bundled into a single directory that, to the end user, appears to be one file
    Windows has no exact equivalent

    @Dan P I'm not using SQLite at all. The app never writes into the files in the RequiredFiles folder, but there are other folders containing text files that are read and written by the app.

    On macOS, and WIndows, this may cause you issues since you cannot write to the internals of a mac App bundle
    And on Windows if the files are in a protected folder then a user may also not be able to write to them

    In both cases you're better off creating a directory in SpecialFolder.ApplicationData that is for files YOUR application reads and writes that users will have access to manipulate

    @Dan P The code I showed in my first post has been working fine for 25 years, and fails only when the package is compressed and then expanded on a different computer. Something is not restored when the package is expanded.

    It probably is expanded
    But depending on where the application was unzipped it can fail for other reasons hving to do with security etc
    Recent changes in macOS and Windows make what used to be common practice no longer "safe" and so your code has to adopt newer and safer practices

  5. Tim S

    Apr 19 Canterbury, UK

    @Dan P So you're absolutely right that I'm not grasping the idea. Are you saying that the app must create the Resources folder at run time start up? And then it copies the sub-folders into that folder?

    A macOS app is actually a folder (called a package). This fact is hidden from the user. You double-click on it and the app runs. If you right-click on an app, and choose "Show package contents" you can see what is actually inside the app. The Resources folder is one such item. The Xojo IDE will create all that for you when you build the .app. As Norman says, Windows seems not to have an equivalent structure, so whereas with a macOS .app the support files for the app are hidden inside it, under Windows and Linux they have to sit alongside it.

    The macOS security is getting tighter with newer OS versions, so that although your app can read the contents of the Resources folder, it should avoid trying to write to it.

  6. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    Thanks, Norman and Tim, for clarifying that quite a bit. I find that my app's Resources folder contains all my graphics elements. Since the IDE asks to find these when I do a build, it's clear that they are put in the Resources folder by the IDE during the build. But my data files can't be put there because the app must be able to write to them at any time.

    The data folders are not created by the IDE. They are created independently and put together with the app in the parent folder by me after the build. Also, some data files within these folders are created at run time.

    So back to the original question. Why does f = GetFolderItem( "RequiredFiles" ) work fine for both Mac and Windows EXCEPT on a Mac when the package has been compressed and expanded on a different computer?

    And most importantly, what can I do about it?
    Would something like f = GetFolderItem.parent.child( "RequiredFiles" ) work?
    Is there some special place the zipped file should be put before it's expanded?
    What "safer" practices are you referring to?

  7. Norman P

    Apr 19 Pre-Release Testers, Xojo Pro Freeport, Bahamas

    You should not put data created at runtime in dirs next to the app on just about any OS as you can experience various issues.
    Files you do create at runtime should be placed in SpecialFolder.ApplicationData in a dir your app creates the first time it is launched.

  8. Tim P

    Apr 19 Pre-Release Testers Rochester, NY

    @Dan P So back to the original question. Why does f = GetFolderItem( "RequiredFiles" ) work fine for both Mac and Windows EXCEPT on a Mac when the package has been compressed and expanded on a different computer?

    Security. Your app has no access to anything except locations explicitly provided by the user via an Open/Save dialog, Temporary Items, and your own child of SpecialFolder.ApplicationData. In modern apps, you need to design as if GetFolderItem() does not exist.

    @Dan Paymar And most importantly, what can I do about it?

    Correctly package your app to work with current security standards. Trying to fight them will only cause you headaches.

    @Dan Paymar Would something like f = GetFolderItem.parent.child( "RequiredFiles" ) work?

    No. You're asking for access to files next to the app, which is not allowed by today's security standards.

    @Dan Paymar Is there some special place the zipped file should be put before it's expanded?

    What ZIP file? The finished package? No, this does not matter.

    @Dan Paymar What "safer" practices are you referring to?

    - Forget GetFolderItem() exists

    • Do not access files without permission (Open/Save dialog)
    • Only read from app folder, never write
    • Only write in temporary, SpecialFolder.ApplicationData.Child("com.my.bundle.identifier"), and where told to with Open/Save dialog

    And these are just starters. You basically have to design your app as if to prove it's not malware because there's just so much out there.

  9. Tim S

    Apr 19 Canterbury, UK

    @Dan P Thanks, Norman and Tim, for clarifying that quite a bit. I find that my app's Resources folder contains all my graphics elements. Since the IDE asks to find these when I do a build, it's clear that they are put in the Resources folder by the IDE during the build. But my data files can't be put there because the app must be able to write to them at any time.

    You can include the graphic elements in your project via the IDE, so you don't have to put up with the IDE asking you for them at build time. I use a folder from the IDE's library pane (see the Project Items section) for things like these. Just drag and drop them onto the folder.

  10. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    Thanks to all for trying to help, but it's all very confusing. You tell me I have to do many things differently. It appears that I would have to completely redesign many parts of my project to do that, but I can't find any examples on how to do that. And all that to avoid a problem that occurs only if the package has been compressed.

    How about if I put the app separate from a folder holding the data folders? I'll call that folder "OpVPdata". If necessary, the end user could use Get Info to set the permissions for that folder. The app would be by itself. Can I then use GetFolderItem to open the OpVPdata folder and its sub folders and then read and write to the text files contained therein?

    What would be the actual code to find the OpVPdata folder? What if the user put the app in the Applications folder and the OpVPdata folder somewhere else?

  11. Dave S

    Apr 19 San Diego, California USA

    @Dan P How about if I put the app separate from a folder holding the data folders?

    Tim explained (I thought quite clearly) why you cannot/should not attempt to do that, and what in fact you should do.

    Perhaps instead of trying to circumvent things, you read Tims post, and ask pointed questions about the areas you are not clear on.

    Unlike the "olden days", modern operating systems do no give you free range of the system anymore

  12. Michel B

    Apr 19 Pre-Release Testers RubberViews.com

    @Dan P How about if I put the app separate from a folder holding the data folders? I'll call that folder "OpVPdata". If necessary, the end user could use Get Info to set the permissions for that folder. The app would be by itself. Can I then use GetFolderItem to open the OpVPdata folder and its sub folders and then read and write to the text files contained therein?

    If you ever want to put the app in the Mac App Store, this is a big no-no.

    Why don't you try to wrap your head around the fairly simple explanations provided in this thread ? I know it is possible. I started developing back in the early eighties, when none of that was around.

  13. Tim P

    Apr 19 Pre-Release Testers Rochester, NY

    @Michel B If you ever want to put the app in the Mac App Store, this is a big no-no.

    These are no longer MAS only requirements thanks to things like Translocation.

  14. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    All this is so very confusing, I don't even know how to ask pointed questions. And there are probably many other things that would keep my program out of the Mac App Store. That doesn't concern me at all.

    Tim said that the data should not be beside the app, but I didn't see anything about not putting data in a separate folder. In fact, I find that I have several commercial programs that do just that. What about iTunes, iMovie, etc.?

    So here are two pointed questions:
    Why shouldn't I just put the app separate from the data folder?
    What would be the actual code to find that folder wherever it might be?

  15. Tim H

    Apr 19 Pre-Release Testers Portland, OR USA
    Edited 4 weeks ago

    @Dan P So back to the original question. Why does f = GetFolderItem( "RequiredFiles" ) work fine for both Mac and Windows EXCEPT on a Mac when the package has been compressed and expanded on a different computer?

    This is probably due to translocation. MacOS literally moves your app to a sandbox location in order to run it. The data files don't go with it. This is new and very different. You will have to change the way you do things to adapt to it. @Tim P outlined the main points above.

    Basically, MacOS doesn't trust an app that came from anywhere other than the app store and tries to protect itself from it.

  16. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    OK, I can't put the data folders next to the app because that's a no-no, and anyway the app actually gets moved when it's run. So why does that work unless the package has been compressed and expanded?

    And I can't put the data folders in the Resources folder because I'm not allowed to write to things in that folder.

    What does that leave but to put the data folders in a separate folder which I've tentatively called OpVPdata? It seems that it shouldn't be hard to find OpVPdata wherever it might be, but I don't know exactly how to do that. Is there example code somewhere?

  17. Tim H

    Apr 19 Pre-Release Testers Portland, OR USA

    It's not necessarily compress/expand that messes you up, it's expanded from a foreign source that get's you flagged as suspect and therefore sandboxed. I believe there's a way for the user to tell MacOS to not sandbox your app, but that's a manual process.

    As a separate issue, you cannot write to anything in your bundle any more. So what you do is include files in your app's bundle (via a Copy step as part of your build settings) and upon app launch, you check to see if those files already exist in SpecialFolder.ApplicationData and if not, you copy them there. You also can create any files you need there. That should work whether you're sandboxed or not (I think?). From that point on, you read/write to ApplicationData.

    Does that make more sense?

  18. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    OK, so it's the fact that it's an expanded file that makes it suspect. Makes sense.

    What is the oldest Mac system that this would work on? I'd like to be able to run on 10.9 thru latest.

    Is that SpecialFolder.ApplicationData for both Mac and Windows, or do I have to do it differently for Windows? Unfortunately, 95% of my market are Windows users.

  19. Alberto D

    Apr 19 Pre-Release Testers
    Edited 4 weeks ago

    This may help:
    https://docs.xojo.com/SpecialFolder

  20. Dan P

    Apr 19 Farmington, NM or Las Vegas, N...

    OK, I’m envisioning six things on the CD:
    The Mac application: OptimumVP.app
    The Windows application: OptimumVP.exe
    The Windows libs folder: OptimumVP Libs
    The OpVPdata folder, which contains 3 sub folders, each containing several text files
    Read Me First, a pdf document that tells how to install the package
    The User Manual, a pdf document

    To install the package, the user copies the appropriate app to the Applications folder (or maybe to some sub folder) and runs the app from there.

    On startup, the app looks for OpVPdata in SpecialFolder.ApplicationData. If it’s not there, it puts a copy there.

    Questions:
    How do I do that copy?
    If it’s a Windows system, what do I do with the Libs folder?

    The app accesses the Games data folder with
    dim f as FolderItem
    f = GetFolderItem("SpecialFolder.ApplicationData").child("OpVPdata").child("Games")

    Correct?

    Or can I just write
    dim f as FolderItem
    f = GetFolderItem("SpecialFolder.ApplicationData").child(“OpVPdata”)
    and save f for all access to all the data folders?

  21. Newer ›

or Sign Up to reply!