How to distribute Swift Library without exposing the source code? - ios

The first thing I tried is to create a static library but later I found out that it's not supported yet. Apple Xcode Beta 4 Release Notes:
Xcode does not support building static libraries that include Swift
code. (17181019)
I was hoping that Apple will be able to add this in the next Beta release or the GA version but I read the following on their blog:
While your app’s runtime
compatibility is ensured, the Swift language itself will continue to
evolve, and the binary interface will also change. To be safe, all
components of your app should be built with the same version of Xcode
and the Swift compiler to ensure that they work together.
This means that frameworks need to be managed carefully. For instance,
if your project uses frameworks to share code with an embedded
extension, you will want to build the frameworks, app, and extensions
together. It would be dangerous to rely upon binary frameworks that
use Swift — especially from third parties. As Swift changes, those
frameworks will be incompatible with the rest of your app. When the
binary interface stabilizes in a year or two, the Swift runtime will
become part of the host OS and this limitation will no longer exist.
The news is really alarming for me a person who writes components for other developers to use and include in their apps. Is this means that I have to distribute the source code or wait for two years?. Is there any other way to distribute the library without exposing the code (company policy)?
Update:
Is Swift code obfuscation an option at this point ?

Swift is beta now, and even for 1.0 Apple has been pretty clear they're after a restricted feature set -- better to do a small number of things well than to try to do everything.
So for now, there's no way to distribute binary static libraries. Presumably that'll change sometime after Swift 1.0. For now, you can:
Distribute source
Ship a binary framework (instead of a library) if you're okay with the ABI being fragile
Use ObjC for library code
You can always combine approaches, too: e.g., implement the critical (secret) details of your library in ObjC, and ship Swift source that wraps it in a nice Swift API.
Obfuscating code written in a language that's very much subject to change sounds like a recipe for a maintenance nightmare.

I believe the whole approach is wrong. You cannot do something that is not (yet) doable by the technology you are trying to use.
Rationale: Swift is a new language, currently in Beta, and therefore changing. As I see it, this fact means not only that you are not able to ship static libraries, but that (real) developers will not be actually use third-party static libraries. What's the actual use of a library that may not work in the next release of the compiler? The issue gets bigger if you whant to use more than one library, because they might not be compatible! Therefore, even if you would be able to ship static libraries, they wouldn't be actually useful for production environment. So, what's the point?
Suggestion: write your static libraries in Objective-C (or C or whatever "non-beta"). Developers who need third-party libraries (e.g. yours) shouldn't expect them to be written in Swift until Swift is stable. You don't use experimental materials to build real bridges, right? You use well-tested, predictable ones.

From Xcode 9 beta 4, Xcode supports static library with Swift sources.

Related

Module XXX Was Not Built with Library Evolution Support

My iOS app has two dependencies (Alamofire and Charts) that it incorporates using Swift Package Manager.
When I build it, I get this warning wherever I import the modules in question, e.g.:
import Alamofire
Module 'Alamofire' was not compiled with library evolution support; using it means binary compatibility for 'YourApp' can't be guaranteed
What I don't understand is:
Why is this binary compatibility an issue, if my app builds the dependencies from source code using SwiftPM (not embedding frameworks distributed as binaries), and
What should I do about it?
The Alamofire repository's issue threads suggest that Library Evolution Support cannot be added to the current version because it hinders development, however it is supported in the previous major version (4). Perhaps that could be a workaround, but I don't want to perform the major code modifications that would result on my app from downgrading Alamofire.
I think the point is that with binary compatibility we don’t have to embed the Swift language frameworks into the app; the system Swift language frameworks will keep working for your app even if the language evolves in the future, without your having to recompile the app. Hence the name, library evolution.
So without that guarantee, the language will be embedded into the app, swelling its size and losing the other advantages of binary stability, such as the ability of your app to take advantage of faster code in the system frameworks when they improve things in the future, etc.
You can probably test that theory by building the app and looking inside it.
So if I’m getting this right, that is the sense in which Alamofire is holding you back, and explains the warning.

Can't Use Swift-Generated Shared Framework in Objective-C

This is a variant of the old "dyld: Library not loaded: #rpath/libswiftCore.dylib" problem. I'm pretty sure I know what the issue is, but I don't have any ideas on how to fix it.
I'll reference the project I'm working on, so I don't clutter the question with huge blocks of code.
The project generates a dylib that can be thrown into another project, and abstract a huge block of coding for developers (a communication layer of a client/server system).
I want the framework to be as simple as possible to to use; even if that means making it a big fat pig. I just want people to be able to toss it into their project (Swift or ObjC), and not have to worry about playing around with different variants for things like simulators and devices.
I use a variant of the old Wenderlich script to lipo the executables for x86 and ARM together.
Note the commented-out section. There be draggones.
Works great. In Swift.
Objective-C, not so great. That's because of the various Swift frameworks that need to be carried into the Objective-C program.
I switched on the embed frameworks setting, and the target dutifully gives me all my frameworks.
The problem is that each architecture has frameworks for ONLY that architecture. They aren't "fat" frameworks, so my hand-built "fat" framework really is kinda skinny, because it will only work on certain architectures.
My question is whether or not there's a way to ensure that the Swift frameworks I embed can be made "fat," or if I just have to give up, and package different variants of the framework for Objective-C programmers.
Any ideas?
I'm giving up on this sucker.
You cain't git thar f'm here.
This library will be Swift-only.

Swift compatibility between versions for a library

I'm distributing libraries for other developers to use (http://empiric.al). I've noticed that between swift versions, even 2.0 to 2.1, I'll get Module file was created by a (newer/older) version of the compiler.
I need to be distribute in a future-proof way.
How can I make sure my compiled frameworks can be used by newer versions of Swift in the future so I don't have to recompile as soon as Apple puts a new beta out?
From Apple's website:
Binary Compatibility and Frameworks
While your app’s runtime compatibility is ensured, the Swift language
itself will continue to evolve, and the binary interface will also
change. To be safe, all components of your app should be built with
the same version of Xcode and the Swift compiler to ensure that they
work together.
This means that frameworks need to be managed carefully. For instance,
if your project uses frameworks to share code with an embedded
extension, you will want to build the frameworks, app, and extensions
together. It would be dangerous to rely upon binary frameworks that
use Swift — especially from third parties. As Swift changes, those
frameworks will be incompatible with the rest of your app. When the
binary interface stabilizes in a year or two, the Swift runtime will
become part of the host OS and this limitation will no longer exist.
Until the Swift ABI (application binary interface) stabilises (I'm guessing another year or two) the only way to distribute libraries that will work across different Xcode versions is to distribute the source code. Cocoa pods and Carthage are both good tools for making library distribution easier but for Swift code they will still rely on source code being available.
It might be possible to have an Cocoapod that detects the version of Xcode it is run with and then downloads and provides the correct build of your library but you will still need to build the libraries for all Xcode versions that you want to support and recompile every time Apple release a new Xcode but at least the user wouldn't need to download a new version manually.

Does the Swift toolchain eliminate code that is never called?

If I create an Xcode project with the iOS Single View Application template and choose Swift for the language, will the compiler exclude from the release build (binary) functions that never get called?
I'm wondering because I want to include a third-party library that has a lot of superfluous classes & functions, and I want to keep my app small & fast.
While I agree with comments, it is unlikely to impact performance in any significant way even if it was included...
Xcode 6 uses Apple LLVM Compiler Version 6.1, depending on how closely related it is to LLVM Developer Group's version the optimization feature is available http://llvm.org/docs/Passes.html with options such as -dce: Dead Code Elimination, -adce: Aggressive Dead Code Elimination.
One way to know for sure what is included is checking the assembly output using -emit-assembly option in the swift compiler and review the output, or opening the binary in a disassembler such as Hopper ( http://www.hopperapp.com/download.html )

iOS SDKs: Renaming a lot of classes

I'm developing an iOS SDK that integrates other SDKs (Facebook SDK 3.5, for example).
To prevent collisions and allow my customers to import those SDKs as well, I want to rename all of the classes/enums in my code (for example, rename FBSession to RDFBSession, etc).
Is there an easy way to do this instead of going class-by-class and using Xcode's rename feature?
Apple provide a command-line tool called tops(1) that is designed for scripting large-scale code refactoring (renaming C functions, Objective-C methods, classes, and other tokens):
tops -verbose replace "FBSession" with "RDFBSession" Sources/*.[hm]
If you have a lot of replacements, you can put all of the replace... commands into a file that you pass with the -scriptfile option. The man page has more information on the more complex commands/options (and examples).
Xcode also offers textual Search and Replace. This will be faster than individual refactors, but it is ultimately less automated. You can make the step by step refactoring faster by first minimizing the project to the relevant dependencies/sources (if possible).
However, renaming the declarations in a library will not alter the symbol names of its associated binary. If it is distributed with a binary, then renaming will just result in linker errors or (in some cases) runtime errors.
The best idea if you need to use a 3rd party library which your clients might also use is to simply inform them they need to link the library with their app, then publish the version(s) the current release supports so they know they have some extra testing if they go too far ahead with some libraries.
I think that a better approach than simply renaming your classes would be to download Facebook's open source code, rename the classes there and compile a new static library with a set of renamed header files. Then you can be sure that no collisions occur and that you're using symbols that you named yourself.
I must warn you though - working like this may make updating the SDK a nightmare regardless of how you tackle this specific issue.

Resources