How to import a private framework in Xcode 8.3 without getting “Undefined symbols for architecture arm64”

我们两清 提交于 2019-11-30 10:36:12

You will need a .tbd file to link against.

Apple stopped shipping these for private frameworks starting with the iOS 9.3 SDK, but you can generate them yourself with a bit of effort:

  1. Get an IPSW for some recent iOS version (ipsw.me or the iPhone wiki have nice lists).
  2. Unzip the IPSW and mount the root file system (the .dmg that is multiple GB).
  3. Find the shared library cache for your architecture in /System/Library/Caches/com.apple.dyld/dyld_shared_cache_arm*.
  4. Using one of various tools (I prefer jtool), extract CoreDuet from it, with e.g.:

    jtool -e CoreDuet /path/to/dyld_shared_cache
    
  5. Optional: Do step 4 for multiple architectures, then combine the extracted files to a fat binary:

    lipo -output CoreDuet dyld_shared_cache_*.CoreDuet
    
  6. Using either machotbd or my own tool, tbdumpnotes, create a .tbd file from the library/framework you just extracted, e.g.:

    tbdump CoreDuet > CoreDuet.tbd
    

    notes 1. I wrote it, so I'm obviously affiliated.
            2. It's a beta, and it's currently a bit over-zealous with symbols, printing even
                the ones it shouldn't - but so far it has always worked fine for me.

  7. Create a folder structure like so:

    some_path/
        CoreDuet.framework/
            CoreDuet.tbd
    
  8. Either add CoreDuet.framework to your frameworks in XCode, or use these compiler flags:

    -Fsome_path -framework CoreDuet
    
  9. Profit.

Also, if steps 1-6 are too troublesome for you and you merely need the _CDBatterySaver symbol, then you can just use this for your CoreDuet.tbd and be done with it:

---
archs:           [ armv7, armv7s, arm64 ]
platform:        ios
install-name:    /System/Library/PrivateFrameworks/CoreDuet.framework/CoreDuet
exports:
  - archs:           [ armv7, armv7s, arm64 ]
    objc-classes:    [ __CDBatterySaver ]
...

Based on Siguza answer

Newer versions of Xcode uses the tbd v2 format. Here is a .tbd stub file that will compile with the latest version of Xcode.

--- !tapi-tbd-v2
archs:           [ armv7, armv7s, arm64 ]
uuids:           [ 'armv7: CBD84526-2D11-4CF3-83A7-4408DA532D3E', 'armv7s: 37ACF720-FA66-4B2D-8411-09D0B607E1A0',
                   'arm64: 19F91B79-9FA2-4944-9E68-3E632C938AE3' ]
platform:        ios
install-name:    /System/Library/PrivateFrameworks/CoreDuet.framework/CoreDuet
objc-constraint: none
exports:
  - archs:           [ armv7, armv7s, arm64 ]
    objc-classes:    [ __CDBatterySaver ]
    objc-ivars:      [ __CDBatterySaver._connection ]
...
tclem

There's an official tool to generate .tbd files these days, tapi (Text-based API). Not sure when it was released exactly, but it's been around at least as long as Xcode 9.

To generate a .tbd for a binary, you do something like the following. Here I'm using the private SafariShared.framework on OSX. If you need a .tbd for an iOS framework, you'll have to follow the beginning of Siguza's answer to get ahold of a binary, but otherwise, the rest of this process will work.

  1. Make an empty directory for the framework stub named, e.g., "SafariShared.framework":

    $ md SafariShared.framework
    
  2. Run a command like the following to generate the stub:

    $ xcrun tapi stubify -o SafariShared.framework/SafariShared.tbd /System/Library/PrivateFrameworks/SafariShared.framework/SafariShared
    

    The -o argument is the output file and the final argument is the path to the binary (note that it is not the path to the .framework itself; you'll get an error if you do that). Replace both as needed.

  3. There's one potential pitfall. Stub files can contain a list of the programs that are allowed to link with that binary, and if your program isn't listed in that list, the linker will fail. Open up the .tbd in your favourite text editor and look for lines like the following:

    allowable-clients: [ <a bunch of bundle IDs>, ... ]
    

    Delete all of those (there may not be any) and save the file.

Now you're good to go! The stub .framework directory you made in step 1 will work just like a real framework in Xcode. In your Xcode project's general settings, you can click the plus in "Linked Frameworks and Libraries" and add the stub directory.

(You may also have to add the directory containing the stub .framework to the "Framework Search Paths" project setting. It seems flaky as to whether or not that will happen automatically.)

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!