Explicitly Loading Third Party Dylibs Without Violating App Store Connect Policies

I am trying to build a Swift app for iOS which depends on an open-source API called BrainFlow. BrainFlow is written in C++. Due to App Store restrictions, the API must be built by hand into a framework so that it can be signed with my developer certificate. So that's what I did. I now have a signed framework that I can embed in my app and that Apple is OK with.

BrainFlow depends on a third-party library called SimpleBLE, an open-source API for connecting to BLE devices. So I built that too into its own signed framework. So far so good.

The problem comes when my app tries to connect to a BLE device via BrainFlow. BrainFlow is designed to explicitly load its third-party libs like plug-ins, and it is hardcoded to assume that all dylibs are located in the same directory. However, when I build the BrainFlow framework so that it embeds the SimpleBLE dylib in the same directory as the BrainFlow dylib, App Store Connect rejects my app due to a policy violation.

One solution might be to query dyld and have it return the resolved location of the SimpleBLE dylib. For example if the dylib is referenced as @rpath/libsimpleble-c.dylib, then the query would return its full path after resolving @rpath. I do not know how to do that or even if it's possible.

Another solution might be to embed the SimpleBLE dylib into the BrainFlow framework in such a way that it does not violate App Store policy. Again I am unable to figure out how to do that or even if it is possible.

The relevant BrainFlow code can be found in the init_dll_loader() function of the following code:

https://github.com/brainflow-dev/brainflow/blob/master/src/board_controller/ble_lib_board.cpp

That function calls DLLLoader(), which can be found here:

https://github.com/brainflow-dev/brainflow/blob/master/src/utils/inc/runtime_dll_loader.h

Thanks in advance for your thoughtful suggestions and comments.

Replies

Progress! I hacked the BF code (in my local repo) and now I can connect to my Muse headset and distribute my app to TestFlight via App Store Connect!

I changed line #42 in ble_lib_board.cpp to read:

std::string lib_name = "../libsimpleble-c.dylib.framework/libsimpleble-c.dylib";

According the man page for dlopen(), a codesigned app with entitlements (which means any iOS app uploaded to the App Store) must use full paths for its dylibs. So my hack gives us a full path, but relative to the location of the calling binary, in this case libBoardController.dylib. According to an error message I received recently from App Store Connect, all frameworks must be located under <App Name>/Frameworks, so that at least gives us a basis for forming the full paths.

According to the same man page, dlopen() should also use @rpath, which is built into the calling dylib. That would be I think the optimal solution, so I will play with that next.