6

I am building an iOS app using PJSIP library with H264 support. When building H264, I get 1 .a file and 2 .dylib files. I tried to use the .dylibs in my project by adding as "Embedded Libraries" and also by creating a separate framework and then adding it to "Embedded Libraries". But when uploading build to App Store, I'm getting errors "ERROR ITMS-90206:...", "ERROR ITMS-90171:..". All points to using external dynamic libraries in project. I followed https://developer.apple.com/library/content/technotes/tn2435/_index.html#//apple_ref/doc/uid/DTS40017543-CH1-TROUBLESHOOTING_BUNDLE_ERRORS-EMBEDDED__DYLIB_FILES

But they are asking to follow steps in "Adding A Framework Target". I cant figure out how to create a framework with only 2 .dylib files and no other source code or header files. Please show the steps for embedding .dylib files into iOS app for App Store submission.

Rounak
  • 301
  • 3
  • 11

5 Answers5

6

I was able to submit an app with a .dylib by creating a framework first. I tried the method described in the apple documentation, but got errors when submitting to the store ( "invalid bundle. the bundle at xyz.framework contains disallowed file 'Frameworks' )

I used the lipo tool to manually package my .dylib into a framework.

$ lipo -create mylib.dylib -output mylib

Now you get a binary file called 'mylib' Create a folder called mylib.framework and put the binary file in it. Then add an Info.plist ( you can just copy and modify one from an existing framework. ) In the Info.plist, fill out the fields for your framework. The main one to update or add is "Executable" which should be the name of that binary file.

I had another issue where another framework I was using was referencing my original .dylib, which is gone and now inside the framework. To fix this I used the "install_name_tool" to modify the other framework to look for my new framework.

$ cd OtherLib.framework 
$ install_name_tool -change @rpath/mylib.dylib @rpath/mylib.framework/mylib OtherLib

You can read more about that tool and modifying various paths in your libs in this good blog post: https://medium.com/@donblas/fun-with-rpath-otool-and-install-name-tool-e3e41ae86172

Morty
  • 1,436
  • 14
  • 12
2

You must add and embed all your shared libraries (.dylib files) directly to the toplevel application the same way as frameworks. You mustn't put dylibs inside a framework because Apple strongly recommends not to use such frameworks (known as Umbrella frameworks) and doesn't accept applications with such frameworks to AppStore (it is a reason for error ITMS-90171).

As Apple documentation says:

An umbrella framework is a framework bundle that contains other frameworks. While it is possible to create umbrella frameworks for macOS apps, doing so is unnecessary for most developers and is not recommended. Umbrella frameworks are not supported on iOS, watchOS, or tvOS.

Alexander Ushakov
  • 5,139
  • 3
  • 27
  • 50
  • 2
    Hi, If I put the .dylibs into the My.App/Frameworks folder Apple rejects it because `Invalid Swift Support - The SwiftSupport folder is missing. Rebuild your app using the current public (GM) version of Xcode and resubmit it.` Could you please let me know if the iOS app can contain .dylib files or they need to be converted into frameworks? – smaryus Oct 26 '18 at 10:59
  • @smaryus I have the same issue. See https://stackoverflow.com/questions/53818772/embedding-a-dylib-inside-a-framework-for-ios Did you resolve it in the end? – Adamski Dec 17 '18 at 16:19
  • Yes, but it got complicated. We made from all the .dylibs frameworks. Then the executable app is parsed and all the references to the dylibs are replaced with the path to the framework/library name. – smaryus Dec 19 '18 at 08:49
  • 2019, ended up having exactly that problem with Invalid Swift Support. Did you ever solve this issue @smaryus? – Daniel Stephens Oct 02 '19 at 16:10
  • 1
    Yes, we changed the dylibs to frameworks and use the frameworks at linking. You can try to recreate the project for libs and change the compilation output from dylibs to frameworks. Or the more complicate way manually create the minimalist framework structure and us it at linker with your application. – smaryus Oct 03 '19 at 09:20
0

Not enough reputation to comment, but Morty's answer worked for me.

I ended up writing a shell script for a post-build phase to do this automatically.

Helpful Tip for the rpath:

If you were building the .dylib file from source, you can change the rpath value in the project settings to be the MyFramework.framework/MyFramework executable that it will be packaged into by the lipo tool.

This will save you an extra step post-build

  • This does not provide an answer to the question. Once you have sufficient [reputation](https://stackoverflow.com/help/whats-reputation) you will be able to [comment on any post](https://stackoverflow.com/help/privileges/comment); instead, [provide answers that don't require clarification from the asker](https://meta.stackexchange.com/questions/214173/why-do-i-need-50-reputation-to-comment-what-can-i-do-instead). - [From Review](/review/late-answers/30871026) – ajmccall Jan 27 '22 at 08:51
0

Not enough reputation to comment, but I came across this problem and Morty's answer helped me very much. So as not to make mistakes, you can create a framework project, compile it once and then you can follow Morty's answer. Issues the lipo command, copy the resulted binary into the root of the framework directory and then open terminal where the framework directory is and issue the install_name_tool command like this: install_name_tool -id @rpath/framework_directory/binaryname framework_directory/binaryname

Using the above we could submit an application with the framework included to the App Store and got accepted.

s840109mm
  • 43
  • 6
0

While the answer of @Morty points you in the right direction, it leaves a lot open to interpretation and didn't work for me, so here's what I had to do:

Open a terminal at your Mylib.dylib file and run

$ lipo -create Mylib.dylib -output Mylib 

Create a folder with the same name as the created binary.framework and mirror this folder structure:

.
└── Mylib.framework
    ├── Mylib <- Binary created by lipo
    ├── Headers
    │   └── Mylib.h <- Symbols you want to access from the binary
    ├── Info.plist
    └── Modules
        └── module.modulemap

Minimal Info.plist file for iOS Device:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
    <key>BuildMachineOSBuild</key>
    <string>XXXXX</string> <- See Mac System Report/Software
    <key>CFBundleDevelopmentRegion</key>
    <string>en</string>
    <key>CFBundleExecutable</key>
    <string>Mylib</string>
    <key>CFBundleIdentifier</key>
    <string>some.bundle.identifier</string>
    <key>CFBundleInfoDictionaryVersion</key>
    <string>6.0</string>
    <key>CFBundleName</key>
    <string>Mylib</string>
    <key>CFBundlePackageType</key>
    <string>FMWK</string>
    <key>CFBundleShortVersionString</key>
    <string>1.0.0</string>
    <key>CFBundleSupportedPlatforms</key>
    <array>
        <string>iPhoneOS</string> 
    </array>
    <key>CFBundleVersion</key>
    <string>1</string>
    <key>MinimumOSVersion</key>
    <string>16.0</string>
    <key>UIDeviceFamily</key>
    <array>
        <integer>1</integer>
        <integer>2</integer>
    </array>
</dict>
</plist>

Make sure CFBundleExecutable is set to the name of your binary, otherwise you'll get the signing issue: "The code signature version is no longer supported.".

Example module.modulemap:

framework module Mylib {
    umbrella header "Mylib.h"
    export *
}

Now you should be able to add the framework with Embed & Sign to your target, import it in swift via import Mylib and use the symbols defined by Mylib.h. When you run the app, you might encounter the crash Library not loaded: @rpath/Mylib.dylib, which can be fixed with this command in the directory of the binary:

$ install_name_tool -id @rpath/Mylib.framework/Mylib Mylib
jacksoor
  • 353
  • 1
  • 12