XCode objective c functions and python bindings
jpsilverberg230 last edited by
Thanks for your comment on pdf support, but I need to work on this in the future. Right now, I've exported the code to Xcode for a standalone app. Do you know if it's possible to create an objective-c routine and call it with python bindings?
Well, if you compile the obj-c code as a static python library, you should be able to have a python binding to it. It would just need to be a C style function but could contain obj-c code as well.
@C0deH4cker - Actually, this is incorrect (if I'm reading what you're suggesting correctly).
Apple doesn't allow for linked libraries (currently) in applications submitted to the iOS App Store. In addition, any attempt to dynamically load a linked library after your application has launched (say, with a ctypes LoadLibrary or CDLL or similar) with cause your application to terminate immediately.
The reason for this is the sandboxing security model that Apple has in place for their iOS apps. When you submit an app to the App Store for iOS devices, Apple signs 2048 bytes of the application binary when it's distributed to a user that downloads it.
This is what keeps you from using the .ipa distribution file for an app from someone else who purchased the app - the signature is directly tied to your account.
In addition, the signed bytes are directly tied to the hash of the remaining unsigned bytes of the application. If you modify the application, the signature is no longer valid = application doesn't launch.
This keeps people from modifying applications, after they're installed on their iOS devices, and changing what the applications do. Tools like iExplorer / similar allow read/write access to the application filesystem on an iOS device without jailbreaking and if you could modify the application (after it was installed), a.) jailbreaking would be much easier and b.) the iOS security model would be a useless joke.
... which is where we come to dynamically loading linked libraries / loading linked libraries <b>at all</b>.
Since Apple only signs the core executable, if they allowed linked libraries you could change out the linked library (with one of the tools I mentioned above) to one which does SomethingNotApprovedByApple / malicious. In theory they could have done the same signature trick with linked libraries but this would be a bit more difficult since they'd have to modify the App Store distribution method to sign a variable number of executable code files.
This also means that should you somehow get an app past their approval process that has dynamic library loading capability, Apple's programmed in a backup process to iOS to automatically terminate any applications that attempt to do it.
... So: ctypes will work (like it does on Python for iOS) to create C data types, structures, etc. - but as soon as you attempt to load a library with it, your python interpreter app would automatically terminate.
Apple really doesn't want arbitrary <b>native</b> code running on your device that they haven't explicitly approved. Sorry folks.
(There was actually an exploit/bug related to this where a guy got around it by loading arbitrary native code into an array in memory - and then marking the memory as executable code. So he didn't load a library, but it was effectively the same - he could run 'unapproved' native code on the device. He published a proof of concept in the App Store and reported it to Apple. The bug was fixed in the next release of iOS. He was also banned from the App Store and his developer status was revoked.)
@pudquick Notice how I said "static library" and not "dynamic library"? Static libraries, unlike dynamic libraries, result in just a single binary file when programs link against them. This means that there would only be a single file containing executable code in your .ipa file, meaning nothing that Apple would disapprove of.
Also, every app uses linked libraries and some even load them dynamically with dlopen. Apps can dynamically load libraries as long as they are signed by Apple (meaning ones on the root partition as part of the giant dyld_shared_cache).
Also, you must be talking about Charlie Miller's iStocks app which could download and run executable code in a sandboxed AppStore app without the "dynamic-codesigning" entitlement.
Basically, using ctypes, you should be able to dynamically load (with CDLL or otherwise) a system library such as libSystem.B.dylib. It just must be one that already exists in the filesystem or the dyld_shared_cache.
In my original comment, my point was not for him to worry about using ctypes at all. There are python modules written in C (such as cStringIO and others) that can be used directly from python code. Since Objective-C is a pure superset of C, you could write a C-style function (of the form "void foo(int bar, type arg2, etc...)", just a C function) that uses Objective-C code internally. Then, compile that .m file into a static library (.a) and link against it in the final executable. You'll need to look up how to compile a python extension statically so it could be used by the app.
Another alternative is using ctypes if it comes in another update. You could use it to dynamically load libobjc.A.dylib. Then, you have access to objc_msgSend() which opens up a world of opportunities.
Let me make this more clear:
Apple has designed the iOS sandbox such that <b>an attempt to get it to execute</b>, from within the sandbox in a non-Apple signed app distributed via the App Store (like Pythonista) a single byte of native code that is not in the single monolithic executable that is the app itself (ie part of Pythonista, distributed by omz via the App Store) - <b> will result in the offending app trying it (Pythonista) to instantly crash.</b>
Static, dynamic, you name it - if your app tries to redirect the processor to execute native code outside of the bytes in the file downloaded from the App Store, it will crash.
And if you find a way and publish with it (like iStocks) Apple will pull your code and the license to develop in the App Store.
External native code is not allowed. It can break the security model.
The ctypes module in Python for iOS does not allow it. And it would have to be similarly neutered in Pythonista.
Pull apart the .ipa for Pythonista right now (unzip it). The only files outside of the single core executable in it are images, sounds, fonts, plists and python scripts. omz statically linked every single necessary module into that one mega Pythonista executable.
No separate module, provided by a user, will ever be loadable / executable if Pythonista wants to stay in the App Store.
jpsilverberg230 last edited by
Thanks for the comments. Currently, I'm jailbreaking (because this is a personal project and I don't want to spend $100 for my own app).
So let me get this straight: I currently have an xcode project which I exported from Pythonista. If I write an objective-c function which uses native APIs and I link to it from python, this will not be allowed by apple if I ever try to distribute it?
@pudquick I know how an IPA is structured. I know all about Apple's codesigning. I know what can and cannot be executed. What I'm saying is that static libraries are acceptable.
Let's say you have a folder called "my_static_library". In it are various C files. To make it into a static library, you first compile each of the .c source files into .o object code files, but they are not yet linked. The next step is to pack all of the .o files into a .a archive. This resulting .a file is a static library.
When you write a program that uses a static library, it is compiled like this:
The program's .c source files are compiled into .o files. Then, the linker takes these .o files and links them together with the .o files that it extracts from the .a static library archive. In the end, all of the .o object files are combined and linked together into one executable file. The .a file and the .o files are never shipped with the application, just the resulting executable.
You are thinking that I'm talking about using external libraries in Pythonista, which is not what I'm saying at all. jpsilverberg said he exported his project to Xcode and was working from there. Therefore, it IS possible to use your own native code and call it from python.
@jpsilverberg You can definitely submit an app written in python that makes use of Objective-C. You just need to get it all into a single executable file.
@C0deH4cker - Please accept my apologies. You are correct. I 100% missed that jpsilverberg was <b>not</b> attempting to do this from within Pythonista.
@jpsilverberg - C0deH4cker is correct (and this is what I touched on in part of my earlier commentary about 'single file'.)
As long as the Objective-C code you attempt to get python to call is compiled into the single application executable, you should be ok.
An example of this is the 'scene' python object in Pythonista. It's not pure python. It's a chunk of ObjC code that's compiled into the Pythonista core executable that exposes a python interface to interpreted scripts.
I haven't exported an Xcode project yet with Pythonista, so there's one thing I don't know which may possibly still be an issue:
If the Xcode project doesn't contain at least one .m / .c source file (with the Pythonista python interpreter as a static lib - or even more unlikely as pure source), you're going to be very hard pressed to find a place to insert your custom ObjC code into the final executable.