Restated: Mac Sandbox Container Folder Creation Problem

Deploying to Mac OS? Ask Mac OS specific questions here.

Moderators: Klaus, FourthWorld, heatherlaine, kevinmiller, robinmiller

Post Reply
stephenmcnutt
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 94
Joined: Fri Nov 10, 2006 8:58 pm
Contact:

Restated: Mac Sandbox Container Folder Creation Problem

Post by stephenmcnutt » Sun Sep 25, 2016 5:42 pm

I'm restating this issue from my previous post because I understand the issue better now and can explain it more clearly.


For an app to be sandboxed for the Mac App Store, data files need to be stored within the app's container (<bundle_id> = app's container) in the directory shown here...

~/Library/Containers/<bundle_id>/Data/Library/Application Support/<app_name>/

Or, to be specific to my app...
~/Library/Containers/com.classroomquizshow.classroomquizshow/Data/Library/Application Support/Classroom Quizshow/

reference: https://developer.apple.com/library/con ... ndbox.html

Those folders are created automatically by MacOS for sandboxed apps--except that final folder, <app_name>, or in my case "Classroom Quizshow" must be created by the application code.

Problem: The LiveCode folder creation method "create folder" does not work FOR CREATING THIS FOLDER once the app becomes sandboxed.

Here's now I'm using "create folder"...
put specialFolderPath("Home") & "/Library/Containers/com.classroomquizshow.classroomquizshow/Data/Library/Application Support/Classroom Quizshow" into gMacLibraryDefaultFolder
create folder gMacLibraryDefaultFolder

Here is my evidence that "create folder" does not work FOR CREATING THIS FOLDER once the app becomes sandboxed. :

1. Build LiveCode standalone.
2. It functions properly, including creating the "Classroom Quizshow" folder for my data files if I delete the folder before running the app.
3. However, this standalone isn't yet seen by MacOS as being sandboxed. If I check the Mac utility app "Activity Monitor", it says "No" in the Sandbox column.
4. Now I codesign and sandbox the app. If I check the Mac utility app "Activity Monitor", it now says "Yes" in the Sandbox column (though it doesn't function--as described next).
5. If I then delete the "Classroom Quizshow" folder in the Container (because the folder wouldn't exist for a new user), the "Classroom Quizshow" folder is not recreated. Consequently, the app doesn't function.
6. I've tested extensively and determined that the code before the "create folder" line runs fine. Code AFTER the "create folder" line also runs fine, provided it doesn't rely on the existence of the never-created folder.

Therefore I believe "create folder" is not allowed by MacOS to create the <app_name> folder within a sandboxed app's Container.

I believe this is a problem LiveCode needs to address--unless LiveCode already has a method to create this special folder, and I'm just unaware of it. While it's true not all Mac App Store apps use data files like mine does (so others might say, "but my Mac App Store app works just fine"), those that do are supposed to store them in this specific location.

Help? If any of my reasoning is faulty, I'm all ears. I am far from being an expert.

Thanks,
Steve

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3977
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by jacque » Mon Sep 26, 2016 6:08 pm

Once the standalone is sandboxed, you are only allowed to write to select folders. You cannot create or write to the app bundle at all. The OS manages this, not LiveCode. For your purposes, use specialFolderPath("documents"), and create your folder there if it doesn't already exist. Then use that folder path to create and access your data documents.

LiveCode will transparently handle the details of managing the sandboxed file paths. This works on any platform from desktop to mobile.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

stephenmcnutt
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 94
Joined: Fri Nov 10, 2006 8:58 pm
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by stephenmcnutt » Mon Sep 26, 2016 9:17 pm

I'm not trying to write to the bundle. What I'm saying is I'm trying to do exactly what you describe, but it doesn't work.

...EXCEPT, I haven't heard of the special folder path you mentioned and will try it as soon as I get home. Thanks!

stephenmcnutt
Livecode Opensource Backer
Livecode Opensource Backer
Posts: 94
Joined: Fri Nov 10, 2006 8:58 pm
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by stephenmcnutt » Mon Oct 17, 2016 12:46 am

I'm making some progress. It turns out the special file path I need is specialFolderPath("support"). By debugging with some 'answer' lines, I determined the following:

For non-sandboxed apps (my stand-alone app as built by LiveCode),
specialFolderPath("support") = ~/Library/Application Support.

For sandboxed apps (my stand-alone app after code-signing and sandboxing with AppWrapper),
specialFolderPath("support") = ~/Library/Containers/com.classroomquizshow.classroomquizshow/Data/Library/Application Support.

The progress I mentioned is that I'm now able to create the folder into which I'm supposed to put my data. The following works in the stand-alone in both its non-sandboxed and sandboxed states:

create folder specialFolderPath("support") & "/Classroom Quizshow"

I've got one thing still not working. For the sandboxed stand-alone, I can't copy my three data files from the application package into that Classroom Quizshow folder. Here's how I'm trying to do it:

First, here's the part that works to create the Classroom Quizshow folder...

on setFilepathsMacLibrary
--For sandboxed apps (AppStore="yes"), specialFolderPath("support") is ~/Library/Containers/<bundle_id>/Data/Library/Application Support.
--For non-sandboxed apps (AppStore="no"), it's ~/Library/Application Support.
create folder specialFolderPath("support") & "/Classroom Quizshow"
put specialFolderPath("support") & "/Classroom Quizshow" into gMacLibraryDefaultFolder
put gMacLibraryDefaultFolder & "/Questions.rev" into gMacLibraryFilePath_Questions
put gMacLibraryDefaultFolder & "/Teams.rev" into gMacLibraryFilePath_Teams
put gMacLibraryDefaultFolder & "/Settings Saver.rev" into gMacLibraryFilePath_Settings_Saver
end setFilepathsMacLibrary

Then this part establishes file paths to the 3 data files in the app package that I need to copy to the newly created Classroom Quizshow folder in the Library...

on setFilepathsMacPackage
local tDefaultFolder
put the fileName of this stack into tDefaultFolder
set the itemDelimiter to "/"
delete the last item of tDefaultFolder
delete the last item of tDefaultFolder --deleting the last 2 items of tDefaultFolder
put "/Resources/_MacOS/CQdata" after tDefaultFolder
put tDefaultFolder & "/Questions.rev" into gMacPackageFilePath_Questions
put tDefaultFolder & "/Settings Saver.rev" into gMacPackageFilePath_Settings_Saver
put tDefaultFolder & "/Teams.rev" into gMacPackageFilePath_Teams
end setFilepathsMacPackage

Finally, here's how those two handlers are called and how the Classroom Quizshow folder is created...

on openCard
if the environment <> "development" and the platform = "MacOS" then -- for the MacOS standalones
setFilepathsMacLibrary
setFilepathsMacPackage
--If data files don't yet exist in Library, copy them from app package to Library...
if there is no file gMacLibraryFilePath_Settings_Saver then
revCopyFile gMacPackageFilePath_Settings_Saver, gMacLibraryDefaultFolder
revCopyFile gMacPackageFilePath_Questions, gMacLibraryDefaultFolder
revCopyFile gMacPackageFilePath_Teams, gMacLibraryDefaultFolder
set the destroyStack of stack gMacLibraryFilePath_Settings_Saver to true
set the destroyStack of stack gMacLibraryFilePath_Questions to true
set the destroyStack of stack gMacLibraryFilePath_Teams to true
end if

All that works for the non-sandboxed stand-alone, but once it's sandboxed, those revCopyFile statements don't work. In other words, I get the Classroom Quizshow folder created, as I've said, but the three data files aren't copied into it.


It's useful to note the change I made in order to get the "progress" I mentioned above (getting the creation of the Classroom Quizshow folder to work in the sandboxed stand-alone). This is what I was doing before, which didn't work...

create folder specialFolderPath("Home") & "/Library/Containers/com.classroomquizshow.classroomquizshow/Data/Library/Application Support/Classroom Quizshow"

And (again) here's the new thing that DOES work in the sandboxed stand-alone...

create folder specialFolderPath("support") & "/Classroom Quizshow"

Those two file paths are identical--they point to the same folder. But when I use the line containing specialFolderPath("support"), LiveCode knows to translate that into the Objective C or Swift (or whatever it does when building stand-alones) statements that are needed to create that folder in the sandboxed environment. So now I just need to figure out how I have to write the revCopyFile statements so they get the same special treatment that'll work in the sandboxed environment.

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3977
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by jacque » Mon Oct 17, 2016 6:38 am

I think you're making this harder than it has to be. Just as you noticed that specialFolderPath("support") is all you need, the same goes for all the other special folders. You can just refer to those and let LC figure out where the folder actually is on any particular OS. Mainly you just need to know if a folder has write permissions. For Mac you can write to the Application Support folder, the Documents folder, and the Preferences folder. Apple says we should use App Support instead of Prefs now, but hasn't forbidden use of Preferences. You can also write to any location the user chooses via an Open File dialog, but if the user didn't choose the location, the app can't write there.

Here's the basic idea, and should be all you need. I'm not using revCopyFile, since I prefer the URL syntax:

Code: Select all

on moveFiles
  put specialFolderPath("support") & "/Classroom Quizshow" into tDestFolder
  if there is no folder tDestFolder then create folder tDestFolder
  put specialFolderPath("resources") into tSourceFolder
  put url ("binfile:" & tSourceFolder & "/Questions.rev") into url ("binfile:" & tDestFolder & "/Questions.rev")
  put url ("binfile:" & tSourceFolder & "/Settings Saver.rev") into url ("binfile:" & tDestFolder & "/Settings Saver.rev")
  put url ("binfile:" & tSourceFolder & "/Teams.rev") into url ("binfile:" & tDestFolder & "/Teams.rev")
end moveFiles
That's untested, but should get you close. I think you could substitute revCopyFile if you want. I rarely use it any more.

BTW, if the destroyStack is set to true in the source files, you don't have to set it on the newly created copies in App Support, they will retain the setting when they're copied.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3977
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by jacque » Mon Oct 17, 2016 8:23 pm

I may have found your problem. This bug was just posted: http://quality.livecode.com/show_bug.cgi?id=18619 On Mac, specialFolderPath("resources") returns correctly in the IDE but incorrectly in a standalone. I'm sure this will be fixed very soon, but for now you can revise the script to account for the discrepancy. The revision won't affect future builds even after the bug is fixed.

My sample script would look like this now:

Code: Select all

 on moveFiles
      put specialFolderPath("support") & "/Classroom Quizshow" into tDestFolder
      if there is no folder tDestFolder then create folder tDestFolder
      put specialFolderPath("resources") into tSourceFolder
      if last char of tSourceFolder = slash then delete last char of tSourceFolder --> bug fix
      put url ("binfile:" & tSourceFolder & "/Questions.rev") into url ("binfile:" & tDestFolder & "/Questions.rev")
      put url ("binfile:" & tSourceFolder & "/Settings Saver.rev") into url ("binfile:" & tDestFolder & "/Settings Saver.rev")
      put url ("binfile:" & tSourceFolder & "/Teams.rev") into url ("binfile:" & tDestFolder & "/Teams.rev")
  end moveFiles
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

wprothero
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 54
Joined: Tue Sep 20, 2011 4:57 pm
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by wprothero » Thu Oct 27, 2016 12:16 am

Jacqueline:
I haven't tried to sandbox and app. But what I get from this is that I need to have my app copy all data files from wherever they are, to the "support" folder. Is this done in a preOpenStack handler? Then there must be a test, for subsequent launches of the app, to see if the files have already been copied?

jacque
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 3977
Joined: Sat Apr 08, 2006 8:31 pm
Location: Minneapolis MN
Contact:

Re: Restated: Mac Sandbox Container Folder Creation Problem

Post by jacque » Thu Oct 27, 2016 8:32 pm

wprothero wrote:Jacqueline:
I haven't tried to sandbox and app. But what I get from this is that I need to have my app copy all data files from wherever they are, to the "support" folder. Is this done in a preOpenStack handler? Then there must be a test, for subsequent launches of the app, to see if the files have already been copied?
That's right. If the files have been included in the Copy Files pane in standalone settings, they will be in specialFolderPath("resources") in the standalone. The destination folder has to be writeable, usually that's specialFolderPath("documents") for user-created data but for app files on Mac, it's usually specialFolderPath("asup") which is Application Support.

You can do the copying almost any time before you need the files. That is most commonly on startup or preOpenStack, but it's up to you. Then on subsequent launches you can check to see if the files exist, and copy them again if not.
Jacqueline Landman Gay | jacque at hyperactivesw dot com
HyperActive Software | http://www.hyperactivesw.com

Post Reply

Return to “Mac OS”