Closed
Description
Describe the bug
Via @johnfhima at #175 (comment)
Apps packaged using this support package are being rejected by the App Store due to app structure.
Steps to reproduce
- Generate a HelloWorld app for iOS
- Push that app to TestFlight
- See error "Invalid Bundle Structure - The binary file '...' is not permitted. Your app can’t contain standalone executables or libraries, other than the CFBundleExecutable of supported bundles."
Expected behavior
App should not be rejected by App Store.
Environment
- Operating System: iOS, possibly macOS
- Python version: all
Additional context
The error message referred to by the App Store links to this document. It suggests the
[@mhsmith edit: This error is also discussed at Technical Note TN2435]
A similar problem likely exists for macOS apps pushed to the App Store.
It's possible the app_packages and python-stdlib folders need to be moved to a "fake" Python framework package in a /Frameworks
location.
Activity
samschott commentedon Feb 8, 2023
Oh, that is annoying! I'm not particularly familiar with either iOS packaging requirements or Python builds, but would a "real" framework build work here? Similar to what the macOS Python installer installs in
Library/Frameworks/Python.framework
on macOS?freakboy3742 commentedon Feb 9, 2023
That's definitely going to be my first pass at a solution. The problem that I foresee is that I'm don't know how aggressive App Store validation is on having "a single library with the same name as the framework" as a requirement. We need to have dozens of .so files, named as .so files, in specific directory structures. I certainly hope we don't need to process every Python module into it's own
.framework
so that iOS is happy...rickymohk commentedon Mar 1, 2023
I am also facing this issue. I tried putting all python stuffs into a framework, and use this framework in an app, but it still produces the error when validating. How does kivy pull this off?
freakboy3742 commentedon Mar 1, 2023
I have checked Kivy for a while, but last time I played with it, they solve the problem by avoiding it completely, and static compiling the binary modules. This approach is guaranteed to work, as all the library code in the main executable, but it prevents distributing packages as binary wheels.
rickymohk commentedon Mar 1, 2023
I understand Kivy is merging the binaries in to the main executable, but I get confused when inspecting the app package content produced by Kivy. There are still .so files inside (e.g. in AppName.app/lib/python3.9/site-packages/) . So I wonder 1. why it still contains .so files when they already merge the binaries into the main exe and 2. why app store validation doesn't care about these .so files.
freakboy3742 commentedon Mar 1, 2023
Like I said, I haven't looked at Kivy for a while, so I don't know for sure. However, (a) are you sure they're included in the final published app bundle, not just the intermediate compilation artefacts; and (b) that Kivy apps are accepted by the iOS App Store? (b) in particular doesn't seem especially likely, but it would be an explanation.
rickymohk commentedon Mar 2, 2023
After further inspection, turns out that the .so files packaged in the Kivy app are empty files, probably just placeholders. They use a custom importer to redirect the .so import for precompiled modules. Now I am able to use a Kivy generated XCode project as a barebone (without compiling the kivy recipe, only compile python and numpy), rename its main function and expose by a bridging header, then add my Swift files with new entry point and start develop with Swift and PythonKit from there. This way it passes the app store validation and successfully uploaded to TestFlight for internal testing. Though I haven't tried to submit for review yet.
johnfhima commentedon Mar 2, 2023
Hi @rickymohk, could you provide some documentation/additional explanation about how can I implement your solution?
This would be really helpful.
rickymohk commentedon Mar 2, 2023
Forgive me if it is not suitable to talk too deep into Kivy in this BeeWare thread. Here is how I did it:
pip install kivy-ios
toolchain build numpy
toolchain create AppName ./dummyapp
An XCode project folder named "appname-ios" will be createdPYTHONHOME
,PYTHONPATH
,load_custom_builtin_importer()
,Py_Initialize()
, etc.) fromint main(int argc, char *argv[])
into avoid initPython()
Py_Finalize()
since it breaks numpy (It throwsPython exception: No module named '_posixsubprocess'
when using numpy ifPy_Finalize()
is called. I figured this out by trial, don't know exactly what it does or its impact. Will be happy if someone could explain it)int main(int argc, char *argv[])
andvoid export_orientation();
void initPython();
into it@main
in it, such as your SwfitUI App, or AppDelegate if you use Storyboard), with create bridging header file#import "main.h"
in the bridging header (e.g. appname-Bridging-Header.h)initPython()
in your entry point then use PythonKit to invoke Python codes.johnfhima commentedon Mar 2, 2023
@rickymohk Thanks a lot for your help. I am trying to follow your instruction but I don't really know what is the necessary part of the main function that should be moved to the initPython function.
In case you feel it is not appropriate to give more information about ivy on this thread maybe you could send it to me by email (in my GitHub bio).
Thanks a lot again, it is few weeks I try to find a solution
rickymohk commentedon Mar 2, 2023
This is how my
void iniyPython()
ending upjohnfhima commentedon Mar 4, 2023
@rickymohk
Did you succeed to install cocoa pods dependencies?
Trying to install TensorFlow lite but it leads to several errors (while in a non ivy project it is working fine).
ydesgagn commentedon Apr 23, 2023
@freakboy3742 let's try to talk 15 minutes this week. This is easy to fix.
-shared
instead of-bundle
for all Apple SDKs. We need to update the patch files for all branches and I'm not too sure how to do it. When I tested it, there is always something failing, so clearly I was not doing the proper thing. Currently when you runfile math.cpython-310-iphoneos.so
you haveMach-O 64-bit bundle arm64
. After the change, it should beMach-O 64-bit dynamically linked shared library arm64
lib-dynload
or many frameworks. The load time of an iOS app is proportional to the number of dynamically linked shared libraries loaded so might be best to let the users add only the frameworks that they really need.I have a bash script I can give you to create the frameworks above.
Ping me and we can align to close this.
Briefcase will also have to be changed when downloading pre-built wheels to extract the .so and create the frameworks on the fly (same bash script can be used as above).
1 remaining item
lin-it commentedon Jun 1, 2023
There is another problem I found that .so cannot be used in the online package of appstore
freakboy3742 commentedon Sep 7, 2023
FYI - The PRs that have been linked to this ticket are sufficient to resolve the problem; Travel Tips has been updated and published using pre-release versions of these PRs: https://apps.apple.com/au/app/travel-tips/id1336372310?platform=iphone
KodaKoder commentedon Sep 17, 2023
Will the dylib update / App Store support be merged on the main or we have to use the dylib branch?
Thanks
freakboy3742 commentedon Sep 17, 2023
@KodaKoder It will be merged - we just need to get everything polished first. There's a lot of moving pieces that we need to be finalised:
We're also using point (4) as an opportunity to rework how we build dylib wheels, integrating
crossenv
rather than the ad hoc approach we've used to date.This is my personal top priority at the moment; I'm hoping to have things finalised by the end of the month.
ydesgagn commentedon Sep 18, 2023
@freakboy3742 let me know if I can help with something.
KodaKoder commentedon Sep 18, 2023
I will test the branch today with a little an app I will report if I encounter any problems
freakboy3742 commentedon Sep 18, 2023
@KodaKoder You may want to wait until I've flagged the PRs as ready for review before starting on that testing. I'm still making changes that will impact on your ability to test this code.