Flutter desktop app for MacOS using extra binaries crashes when exported - flutter

I want to distribute a Flutter desktop app outside of App Store. The app includes some extra binaries using the assets key in pubspec.yaml. The binaries end up in this directory inside the app:
flutter_sample.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets/bin
So that's what I use with Process.run(...) and it works locally. However, if I try to notarize the app in Xcode and export it then app will crash immediately when trying to run an included binary. I opened Console and found the following entry in launchd.log corresponding to the time the app crashed:
2022-01-07 08:28:04.875197 (gui/501/application.com.example.flutterSample.1772919.1772925) : removing job: caller = runningboardd
2022-01-07 08:28:04.875204 (gui/501 [100020]) : removing service: application.com.example.flutterSample.1772919.1772925
2022-01-07 08:28:04.875309 (gui/501/application.com.example.flutterSample.1772919.1772925) : internal event: PETRIFIED, code = 0
2022-01-07 08:28:04.875311 (gui/501/application.com.example.flutterSample.1772919.1772925) : job state = removed
I wasn't able to find any other information about the error. If I enclose the code using Process.run in a try-catch block it doesn't change anything, the entire application crashes anyway. The same happens if I use a zone or onError handler as described on the handling errors page in Flutter docs.
Extra details:
I've disabled com.apple.security.app-sandbox in the *.entitlements files, with it running the processes didn't work even locally
I've enabled hardened runtime in Xcode, it was required to notarize the app.
the app also crashes if instead or exporting from Xcode I plainly archive the build directory (with tar) and send it via internet (or set com.apple.quarantine with xattr). It won't crash if I just pack and unpack it without marking it as quarantined. That makes sense but I expected that notarizing the app would fix it.
So, what can I do to prevent these crashes, or at least get more details when they happen so I can investigate further?

As it turns out, it was an issue with paths. If I go to my project directory and then enter the debug build directory:
$ cd build/macos/Build/Products/Debug
then from this point I can access two identical asset directories:
$ ls -lh App.framework/Versions/A/Resources/flutter_assets
(output omitted)
$ ls -lh flutter_sample.app/Contents/Frameworks/App.framework/Versions/A/Resources/flutter_assets
(the same output, omitted)
As it turns out, I was actually trying to call the binary in the first asset directory (even though I posted the second one in the question). And apparently the other one is correct when the app is packaged for distribution. After changing this the binaries work in the exported, notarized app.

Try to firstly copy your binary from assets folder to somewhere else. Let's say copy to /tmp/myfile. Then ensure you have executable permission to it (chmod +x /tmp/myfile using shell; should have sth similar using code). Then execute that binary.
This is a common practice, at least for platforms like Android. Because in android, an asset does not have a "normal" path so you have to copy it out, IIRC.
If this method works, it is great; even if not, now you can manually call /tmp/myfile in a shell to see what is happening.

Related

flutter blank screen on desktop(windows)

Running my application on another Windows machine results in a blank window. I works fine on the development machine.
I have included all the dll-files + data folder + 3 extra dll files mentioned on the Flutter website.
I have also ran "dependencies" on the resulting .exe file and can't see any missing dll's.
Compiling the "mydemo" application works fine, so I assume there are some other external files my application needs.
I have tried looking through the output of "flutter run -v" to find any clues of extra files needed, but can't see anything useful.
What is the preferred way to tackle a problem like this? How can I find out what files/resources are missing to distribute my app? Is there a way to use the "debug" version on the other machine instead and bring out the debug console window? I would guess that would show me errors when the app tries to load the missing resources.
Check if any package you depend on has some additional file requirements: for example, I'm using sqflite_common_ffi in some of my projects, which needs an additional DLL file to run. I don't know what you're referring to 'dependencies' ran on the EXE, though.
In any case, when I can't get any good output or error from a project, I do this: open up Windows prompt, go to the directory where you have put all the required files, and run
your_exe_file >> logFile.txt 2>&1
which will output the standard output and the standard error to the file. The log file name and extension don't really matter, it will be a simple text file.
For example, if I dont put the additional DLL for sqflite_common_ffi in the same folder of the compiled EXE, the output of the command above will specifically mention the name of the DLL that is missing.
if you got your project through a repository to run on another windows machine, use the command "flutter pub get"

Is there a method for sharing and syncing the iOS simulator Applications folder

Our sales team often needs to give demos of apps currently in development. We've used a variety of methods to get them installed on their laptops but everything has been very manual.
The initial method we were using had us downloading the source code and compiling each and every project for each and every salesman. Very time consuming and annoying.
Then we got a little smarter and realized that we could copy out the Applications folder for the iOS simulator and just past that over the iOS simulator's Applications folder on each salesman's laptop. Much better, but still the manual part of copying them all over to each laptop.
So I started poking around about some folder syncing options for macs and came across this technique http://www.youtube.com/watch?v=iWoXPWlu_Dk
Very awesome and seemed to meet my need exactly. I had one central shared folder I could throw new iOS applications into and then the salesmen's laptops would automagically sync with that applications folder and new apps would just appear with no need to ever have their laptops here.
Unfortunately, the iOS simulator does not seem to be recognizing the Applications folder when it's a symbolic link or alias. Is there some Mac magic that could make this work? (I'm a Windows guy normally, just recently been working in the iOS world, so there could be something basic I'm missing here).
I'd love to have the Applications folder /Application Support/iPhone Simulator/5.1/Applications be a shared folder that syncs automatically for them, grabbing any new applications we have ready for demos (and getting them updates to old ones). Just seems like a nice smooth way to get them early builds.
We've used services like TestFlight for the actual devices and that's a great option for that, but when they don't have a device handy or are just blasting through demos on their laptops we'd love to have a nice easy process for keeping them up to date with new builds for their simulator install.
First a bit of background, you don't really need this, but I like teaching :).
On Unix, and now MacOS, there are two basic kinds of links. 'normal' links, and symbolic links. Alias, on windows, unix and mac are a kind of symbolic link: the link contains a reference to the original file. Normal, or hard links create a second directory entry that points to the data, if you delete the original file, the OS knows that there is still another entry pointing to it, so it only actually deletes the file (or directory) when all hard links have been removed. The disadvantage of hard links is that they have to be on the same file system, so that the file system can keep count of how many hard links there are.
OK, I've just installed Dropbox, and it seems that it creates a real folder in the user's home directory, so unless you're a complicated disk partitioning scheme, or file vault 1, where the user's home directory is actually an encrypted disk image, you can use a hard link. It also means that you don't need to copy or sync, as Dropbox is already doing that.
One thing not corrected, but didn't actually point out is that in your post, you seem to be copying to /Application Support, not ~/Library/Application Support or /Library/Application Support. Since you've got the basic scheme working without dropbox, I'll assume that is a typo.
Before I give you the commands, you might want to delete the old iPhone Simulator Applications directory with the Finder, instead of using the rm command, as the rm command is potentially very destructive.
OK, finally, the commands to do the linking; the quotes are important whenever filenames contain spaces. This example is for ~/Library
rm -rf "~/Library/Application Support/iPhone Simulator/5.1/Applications"
ln "~/Dropbox/Simulator Applications" "~/Library/Application Support/iPhone Simulator/5.1/Applications"
This should work, you can stop reading now, the rest is just more education :)
Tilde (~) is a short cut for the users home directory. Use the commands without this to work on /Library instead.
If you want to be sure you've got the exact path, you can drag files and folders from a finder window into the terminal, the path gets pasted instead of the file.
If you're messing with stuff in the root filesystem, you might need superuser rights. If you are logged in with an admin account, you can run single commands with superuser access as follows.
sudo ln "/Library/Application Support/iPhone Simulator" fred
The shell asks for your password, and then runs the command for you as superuser.
sudo remembers the authorization for a few minutes, then you have to authenticate again.
Haven't tested this since I only have one Mac, but give this a try:
Install Dropbox
Create a shared folder there and copy your apps from /Users/USERNAME/Library/Application Support/iPhone Simulator/5.1/Applications
Create a shell script to copy them back to the simulator's location, and add it to the shared folder. It should look something like this:
#!/bin/sh
cp -R ~/Dropbox/Appfolder/appname ~/Library/Application Support/iPhone Simulator/5.1/Applications/
Have your users sync their dropboxes to get the files, then run the shell script to copy the files.

Symbolicate crash logs

Q1) How can I symbolicate the entire crash log file. I do have DYSM & APP files with me. Using ATOS command is tedious. My symbolicatecrash is not working.
Q2) If I forgot to capture the DYSM & APP files while generating a build, can I generate & use them after some time given that there is no modification done on that code after the build was generated. Will this be as good as capturing these file at the time of build generation?
A1) Just put DSYM, APP and crash files in one directory. Then open XCode Organizer->iPhone development->Device Logs, and just drag & drop crash log to a list. That's all, if you have a proper dsym file, crash log should appear with symbols in a list.
A2) If there are no modifications done on code, compiler and machine where build was generated, there's some chance. But I never succeed in my attempts to do this.
symbolicatecrash is a perl script that uses spotlight to locate the dSYM files that belong to the app that crashed. If you run symbolicatecrash with the -v (verbose) option you'll see something like:
Searching in Spotlight for dsym with UUID of ...
Running mdfind "com_apple_... == ..."
So, be sure that spotlight works, and the indexing for spotlight is active for the volume where your stuff is located, with the mdutil command: mdutil -s -a
If the volume your archived Apps are on is not indexed be sure to switch indexing on. (As root/sudo: mdutil -i on /Volumes/...)
You can also translate symbols manually using atos. Read more on my blog: http://www.dev-smart.com/archives/389

Forcing code signing refresh in Xcode

In our environment, we share resources across multiple projects and platforms. When building for iPhone, only a subset of those resources are needed. Since that subset is still considerable, we have a manifest file listing what goes in, which limits the copy. We have our own Python script which does the copy, refreshing only the files which have changed.
I have made a Run Script Phase in Xcode to call that script, but I am having a few issues related to the Code Signing phase.
Since we use a separate manifest file, my Run Script Phase cannot specify any input/output file in the Xcode GUI: it varies depending on what is contained in directories at the time. The side effect of this is that Xcode doesn't strictly know what files will get copied (things happen "under the cover", so to speak).
The problem I have is that if I only modify resource files between builds, rebuilding my app will properly call my script, which copies the appropriate files, only Xcode won't rerun the Code Signing step, and won't re-copy my app to my device.
I found that odd, considering that my resource files are indeed listed in the <app_bundle>/_CodeSignature/CodeResources file, but it looks like Xcode determines rebuilds requirements independent of that (likely only files listed in the project file), which is understandable.
I tried playing tricks by touching my app bundle's directory, or the app's binary itself, but it doesn't quite work. Touching the app's bundle directory doesn't seem to do anything, while touching the binary will work, but NOT FOR THE CURRENT BUILD, only the subsequent one (since no input file requires recompilation, Xcode infers no new binary gets generated, but the next time, it will indeed detect that the binary has been touched, and redo both Code Signing and on).
Still, this is quite an imperfect workaround, because:
Having to build twice is error prone
My dSYM file will needlessly get regenerated
Does anyone know of any way to force the Code Signing step in Xcode (from a Run Script, or elsewhere)?
You can call codesign directly from the command line or a shell script, e.g.
codesign -f -s "iPhone Distribution" --entitlements Entitlements.xcent -vv location/MyApp.app/MyApp
Run man codesign to find out the usage.
You can discover all the internal commands run by viewing the detailed build output in Xcode. Select the Build tab, then click the little icon at the bottom left of that window pane - the one that looks like text (it is next to the warning icon). This will show the full build output in a new pane in Xcode.
I created a shell script calling codesign directly so I could re-sign an existing binary using a new certificate and provisioning profile (e.g. after updating some graphics in the binary).
This turned out to be really complicated as Xcode does some subtle stuff as part of its internal build processes (one example: Xcode embeds the provisioning profile in the resulting app binary, but in the process changes some of its values, e.g. the get-task-allow setting). That meant I had to write a tool to generate an appropriate .xcent file from the provisioning profile, depending on whether a Development/Distribution/App Store build is being done. Hopefully none of that will affect you...

Can Xcode include application resource files that are generated during the build process?

I have a bunch of content files for my iPhone app that I generate via shell script. It takes way too long to be a part of the Xcode build process, so I run it periodically.
I don't want to have to continually add these files to my Xcode project in order to get them included my app resources folder. Is there a way to get Xcode to copy the contents of a folder into the app resources at build time? (It'd be a bonus if I could specify other locations, such as the approot documents folder.)
I tried adding a new 'Copy Files Build Phase' to my target, but that didn't seem to work. This seems like a common problem, but I couldn't find anything about it here.
-- Edit (What I did)
Per Jasarien and cdespinosa's suggestions, I did the following in a build script. I decided not to copy to the destination, because that would only work when using the simulator, I don't think that'll work when deploying to a device.
cp -rf "$PROJECT_DIR/mystuff" "$CONFIGURATION_BUILD_DIR/$CONTENTS_FOLDER_PATH/"
-- Edit 2
This doesn't appear to get files onto my iPhone. Any ideas?
You can setup a Run Script build phase in your app's target. Write the script so that it copies the resources into the app bundle.
This is the path i use for output:
${CONFIGURATION_BUILD_DIR}/${UNLOCALIZED_RESOURCES_FOLDER_PATH}
Just copy your files in that directory, it's the bundle (simulator or device).
You can also take a look at my answer here : how to set up a Xcode build rule with a variable output file list?