Titanium JIRA Archive
Titanium SDK/CLI (TIMOB)

[TIMOB-17888] iOS: Add support for Swift libraries in native modules

GitHub Issuen/a
TypeBug
PriorityHigh
StatusClosed
ResolutionDuplicate
Resolution Date2018-04-05T19:23:53.000+0000
Affected Version/sn/a
Fix Version/sn/a
ComponentsiOS
Labelsios8, modules, swift
ReporterShannon Hicks
AssigneeHans Knöchel
Created2014-10-22T15:09:06.000+0000
Updated2018-08-06T17:41:11.000+0000

Description

Modules that have frameworks built using Swift do not work. Modules compile, but when you try to build an app using the module, you get errors:
ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later (@rpath/ChasePaymentech.framework/ChasePaymentech) for architecture i386
As you can see from the error, we attempted to implement the Chase Paymentech SDK. Chase puts the Paymentech SDK download behind a login wall... We can't provide it, but you can sign up (free) and download it. So, to reproduce this error (and possibly fix it), my steps:

Create the module

ti create -n ti.test -p ios --id ti.test -t module -url "http://test.com" -d .

Open up the project in Xocde. Confirm it builds.

Download the library from https://secure.paymentech.com/developercenter/mobilesdk/ios/?WT.mc_id=adc001_sdk

Place the .framework file in /iphone/platform

Drag the file into the source explorer in Xcode. No need to copy it (as it's already in the project). Or you can follow the linking instructions in the paymenttech docs

Edit the module.xcconfig file to reference the framework:

//
// How to add a Framework (example)
//

OTHER_LDFLAGS=$(inherited) -framework ChasePaymentech
The module builds without error for me (both from inside Xcode and from the command line).

Create the application

Drop the built module into the global module cache (Unzipped). For me this is ~/Library/ApplicationSupport/Titanium/modules/iphone

Open Studio

Create a new 2-tabbed app, iPhone/iPad only

Add the module to the application from the tiapp.xml editor

Drop to the command line. 'ti build -p iOS'.

The app will fail to build, unable to find the ChasePaymentech framework

Fix the Xcode project

Open builds/iphone/.xcodeproj

Follow the instructions in the Paymenttech document to both link the framework in the application, and then to copy the framework during the build process.

Place the framework library in a folder accessible to your application.

Select Project Setting and Build Phase. Click on “Link Binary With Libraries” section. Then press “+” button to add the framework.

Click on “Add Other…” and choose ChasePaymentech.framework from the physical location in step 1.

Click “Copy Files”, ensure “Framework” is selected in “Description” drop-down. Click “+” as indicated below.

Select “ChasePaymentech.framework” under “frameworks”.

Under “Project Navigator”, within “Frameworks”, “ChasePaymentech.framework” would have been added.

Attempt to build the application, you will get the error about "ld: embedded dylibs/frameworks are only supported on iOS 8.0 and later"

To Fix it

Build Settings > iOS Deployment Target. Update this to 8.0 App builds successfully...sometimes. When it fails, it appears to fail because it can't find the Chase framework. This suggests that the framework isn't being copied in time to the correct output location before linking.

Comments

  1. Ingo Muschenetz 2014-10-23

    This is not a duplicate. One is using Swift code directly in the library, the other is referencing a Swift library as a dependency.
  2. Ingo Muschenetz 2014-10-23

    I have added my steps to the above description. If they are incorrect, please edit.
  3. me@gmail.com 2014-10-23

    Ingo , the work around is not 100% true. There seems to be a race condition when doing this... my slower mac mini has no issue with doing this, but running on my MBPr fully specked out it works 1 in 10 times or so. The rest of the time I get an error that the SDK (Chase in this instance) can not be found.
  4. Ingo Muschenetz 2014-10-23

    [~mattapperson] When it does work, is the workaround correct? I am more concerned with the general overall flow so that we can then update the tooling to accommodate this.
  5. me@gmail.com 2014-10-23

    It is yes... but there must be something the tooling needs to wait for at some point to prevent the race condition.
  6. Ingo Muschenetz 2014-10-23

    Okay, that's good to know. That means it's a simpler CLI/build process change than something that relates to how we build/link libraries.
  7. me@gmail.com 2014-10-30

    The reason for the issue is: http://aerogear-dev.1069024.n5.nabble.com/aerogear-dev-Swift-Frameworks-Static-libs-and-Cocoapods-td8456.html So basically even if we get it to copy without issue, the fact that ti modules compile to a static lib is a no go at this point...
  8. me@gmail.com 2014-10-30

    So in other words, once you add #import the module can no longer compile. Or when it does it results in the app crashing immediately
  9. Pedro Enrique 2014-10-31

    NOTE: To make the titanium project find the third party library, add the path to the module.xcconfig file. If the module is at the project level (not at the titanium sdk level), the module.xcconfig should look like this:
       OTHER_LDFLAGS=$(inherited) -F$(SRCROOT)/../../modules/iphone/ti.test/1.0.0/platform/iphone -framework ChasePaymentech
       
  10. me@gmail.com 2014-10-31

    Pedro, Yes you are correct, but that is not the issue here. My module.xcconfig looks like this FWIW FRAMEWORK_SEARCH_PATHS=$(SRCROOT)/../../modules/iphone/ti.passbook.paymentech/1.0.0/platform /Library/Application\ Support/Titanium/modules/iphone/ti.passbook.paymentech/$1.0.0/platform ~/Library/Application\ Support/Titanium/modules/iphone/ti.passbook.paymentech/1.0.0/platform OTHER_LDFLAGS=$(inherited) -framework ChasePaymentech
  11. Pedro Enrique 2014-10-31

    I know :) Just giving out a hint to make the "including third party libs" a bit easier. I'm looking into this right now. I think the first thing we need to do is make the module a dynamic library, that's the first step and that's what I'm working on.
  12. Ingo Muschenetz 2014-10-31

    I'm not convinced that the requirement for a module being a dynamic library is an actual architectural requirement, and may instead be a decision Apple has decided to enforce. Please take a look at http://andelf.github.io/blog/2014/06/25/write-swift-module-with-swift-cont/ (you're going to need to use Google translate here).
  13. me@gmail.com 2014-10-31

    I think I might have a path forward without having to do anything too radical... details forthcoming after some more tests
  14. me@gmail.com 2014-10-31

    OK so when building the module we still have 2 issues: - The module Xcode proj displays errors like crazy saying it cant see the frameworks headers - ./build.py will sometimes error out with the same issue. We can build if we keep deleting the modules build dir... not sure the reason for the issue there. However once we do that and follow the fix steps above PLUS in the general tab of the apps xcode proj, under "embedded binaries" we link to the framework we are able to successfully build an app with a module using a swift framework.
  15. Pedro Enrique 2014-11-04

    I'm able to build the module without errors. This is the way the module.xcconfig looks on my end
        FRAMEWORK_SEARCH_PATHS=$(SRCROOT)/../../modules/iphone/ti.testmodule/1.0.0/platform/iphone /Library/Application\ Support/Titanium/modules/iphone/ti.testmodule/1.0.0/platform/iphone ~/Library/Application\ Support/Titanium/modules/iphone/ti.testmodule/1.0.0/platform/iphone
        OTHER_LDFLAGS=$(inherited) -framework ChasePaymentech
        
    Then, I placed the framework in the "platform/iphone" folder at the root of the module folder, create it if not there. After that, delete the "build" folder, build the module normally. Once that's done, introduce the module to your Titanium app the same way you've always done it. Add this to tiapp.xml
        <ios>
        	...
        	...
        	<min-ios-ver>8.0</min-ios-ver>
        </ios>
        
    Run it from Studio, and it will crash. This is what I did to "fix" it. 1. Open the generated Xcode project 2. Drag the third party framework (ChasPaymentech.framework) to Xcode, to the “Frameworks” folder in your project 3. Click on the project name, blue icon on the left bar, so that the App properties appear in the middle section of Xcode 4. Click on the target you’re building, the one without "-ipad” and without "-univesal" 5. Drag the framework, that you previously dragged into Xcode, to the "Embedded Binaries” section of the app properties 6. Click on the project, on top of the targets, and make sure that the “iOS Deplyment Target” is selected to iOS 8 7. Run the app Give this a try and let me know if it works for you.
  16. me@gmail.com 2014-11-04

    Yes this is what I have been doing to get through this project.
  17. Hans Knöchel 2018-04-05

    Work in progress in TIMOB-17887, scheduling for 8.0.0.
  18. Eric Merriman 2018-08-06

    Closing as a duplicate. If this is in error, please reopen.

JSON Source