I am trying to use an Objective-C framework with the Swift programming language for iOS 8 development. This is a specific case of an import but the general problem is:
How do you import an Objective-C framework into swift and get the import recognized?
I am trying to integrate the Parse framework into a swift application using the iOS 8 and Xcode 6 betas.
Here is the technique for Parse framework integration in Objective-C:
https://www.parse.com/apps/quickstart#social/mobile/ios/native/existing
I have downloaded the Parse framework as a compressed archive, extracted it, and imported it into Xcode 6 without any problems. Within my application it appears as a properly formatted framework under the name Parse.framework.
My current thought process is to modify the AppDelegate.swift file in the root directory of my project. Here is the current file without modifications (automatically generated by Xcode upon swift project creation):
https://gist.github.com/fconcklin/e8ef7d8b056105a04161
I have tried to import parse by adding the line import Parse below the line import UIKit. However, Xcode issues a warning that there is no such module found and the build fails.
I also tried creating a file ${PROJ_NAME_HERE}-Bridging-Header.h that contains the Objective-C import of Parse using import <Parse/Parse.h>. This line doesn't throw an error but appears to ultimately make no difference.
After further research I found the solution and realized that I was just confused.
The correct approach is as follows:
Import your Objective C framework by dragging and dropping the framework into an Xcode 6 Swift project.
Create a new Objective C file in your project (File->New->File [Objective C for iOS]).
Accept the prompt (agree) to create a bridging header file between Objective C and Swift.
Delete your newly created Objective C file but retain the bridging header file ${YOURPROJ}-Bridging-Header.h.
In the Bridging header file, import your framework using the standard Objective C import syntax (e.g. #import <Parse/Parse.h>).
This relinquishes the need to perform an import Parse statement in your AppDelegate.swift file. You can now write code that utilizes whatever framework as long as it is imported using the bridging header. It is available throughout your project's Swift files.
Now, if you would like to test Parse integration in your project, you can type Parse. and use code completion to browse the framework and see that the code completion is indicative of a successful import.
However, there is another caveat here that needs to be addressed when using a Bridging Header file. All dependencies of the framework need to be specified in the Bridging Header file as well. In the case of integrating Parse framework into a Swift application your Bridging Header file will look like this:
#import <Foundation/Foundation.h>
// Parse Dependencies
#import <AudioToolbox/AudioToolbox.h>
#import <CFNetwork/CFNetwork.h>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreLocation/CoreLocation.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <QuartzCore/QuartzCore.h>
#import <Security/Security.h>
#import <StoreKit/StoreKit.h>
#import <SystemConfiguration/SystemConfiguration.h>
// Import parse framework
#import <Parse/Parse.h>
Hope this helps.
A "Fool Proof" way of adding a bridging header is as follows:
If you have a Swift project, add a new Objective-C File to your project and Xcode will prompt if you want to configure your project with a bridging header. Press yes.
If you have a Objective-C project, add a new Swift File to it and you will get the same prompt. Press yes.
After you get the bridging header, you can delete the file you just added if you want to.
To add Parse framework to the Swift project:
Add this libaries to the Swift Project.
Paste this frameworks from ParseSDK to your project:
Add a ProjectName-Bridging-Header.h (https://developer.apple.com/library/ios/documentation/swift/conceptual/buildingcocoaapps/MixandMatch.html) (https://stackoverflow.com/a/24272431/1847511) file with such content.
Add path to tie bridging header:
Add the TestCode:
Run the app.
The answer for my problem was different. I had the Framework Search Paths in my project's Build Settings set to recursive when they should have been non-recursive.
In my case, my target has its Framework Search Paths set to $(inherited), which means to inherit the setting from my project.
My project's Framework Search Paths only had one path, $PROJECT_DIR/../External/** (with the two asteriks meaning "search this folder recursively". My Parse.framework file was located in the base level of the External folder.
Changing the path from recursive to non-recursive fixed things for me. Very strange...
Using Objective-C Classes in Swift
If you are going to import code within an App Target (Mixing Swift and Objective-C in one project) you should use bridging header file to expose Objective-C code to Swift code. [Mixing Swift and Objective-C code in a project]
In this post I will describe how to import Objective-C framework to Swift code
Swift consumer -> Objective-C dynamic framework
Xcode version 10.2.1
Create Objective-C framework
Create a framework project or create a framework target
File -> New -> Project... -> Cocoa Touch Framework
//or
Project editor -> Add a Target -> Cocoa Touch Framework
Two files will be generated:
Info.plist - Build Settings -> Info.plist File
<product_name>.h - Build Phases -> Headers. It is umbrella header file which will be open for consumer[About]
Add all .h files to this umbrella file(<product_name>.h)
#import "header_1.h"
#import "header_2.h"
Add Implementation files .m
Select `.m` file -> Select File Inspectors Tab -> Target Membership -> Select the target
//or
Project editor -> select a target -> Build Phases -> Compile Sources -> add files
Add Headers files .h that were listed in <product_name>.h in public zone (header_1.h, header_2.h)[can not do it] [public target membership]
Select `.h` file -> Select File Inspectors Tab -> Target Membership -> Select the target and make it **public**
//or
Project editor -> select a target -> Build Phases -> Headers -> add files to the **public** zone
Build the framework - ⌘ Command + B or Product -> Build
Note: Be sure that you build the framework for the same process architecture as the client code.
Find generated output[Build location]
Products group -> <product_name>.framework -> Show in Finder
The framework includes
Info.plist
Modules folder with:
module.modulemap[About] [Custom modulemap] This file was autogenerated because Build Settings -> Defines Module -> YES
Headers folder with:
files from Headers section. There are public interfaces/definitions
Swift consumer with Objective-C framework
Drag and drop the binary into the Xcode project[About]
Embed binaries[Library not loaded] [Link vs Embed]
Project editor -> select a target -> General -> Embedded Binaries -> path to `<product_name>.framework` file
I will automatically add the framework to:
Project editor -> select a target -> General -> Linked Frameworks and Libraries
Project editor -> select a target -> Build Phases -> Embed Frameworks
Project editor -> select a target -> Build Phases -> Link Binary With Libraries
Add Framework Search paths(FRAMEWORK_SEARCH_PATHS)[Module not found] [Recursive path]
Project editor -> select a target -> Build Settings -> Search Paths -> Framework Search paths -> add path to the parent of `<product_name>.framework` file
Import module to the Swift client code[module_name]
import module_name
More examples here
New Parse framework version need some update.
Such as You should insert libsqlite3.0.dylib in Library Binary With Libraries and update header file with #import and #import
Related
I have a project with multiple targets that one of them uses a special framework. The framework has been written with Objective-C and my project is written with Swift.
So I need to have a Bridging-header file where defines the framework. Now I use the communal Bridging-header file but I don't want to use that framework on the other targets.
I tried to use the Bridging-header file separately for each target but I faced compile error which was couldn't find the framework in those of class files that import it!
- TL;DR
My question is: How can I add an Objective-C framework in the Swift project with multiple targets with considering that it should use in one target as well as the bridging-header file?
After a couple of days, I could manage to solve it.
1) Add a custom flag (MY OPTIONS) as well as #ifdef and #endif on the BridgingHeader.h file. like the following picture:
2) Select Target(specific) -> Build Settings -> Preprocessor Macros then add
MY_OPTIONS=1
3) Select Target(specific) -> Build Settings -> Swift Compiler - Custom Flags -> Other Swift Flags then add
-DMY_OPTIONS
4) On your class add this line to prevent get a compile error when compiling other targets
#if MY_OPTIONS
let specificVC = SpecificViewController()
self.present(specificVC, animated: true, completion: nil)
#endif
I am add Ensembles to my Swift project - found here https://github.com/drewmccormack/ensembles. I have had no luck adding iCloud support to my app and syncing data across devices so hoping this will work.
I have followed the following instructions for adding the framework to my app,
In Finder, drag the Ensembles iOS.xcodeproj project from the
Framework directory into your Xcode project.
Select your App's project root in the source list on the left, and then select the App's target.
In the General tab, click the + button in the Linked
Frameworks and Libraries section.
Choose the libensembles.a library and add it.
Select the Build Settings tab. Locate the Other Linker
Flags setting, and add the flag -ObjC.
This is how it looks in my project, I am unsure if i have done this step right.
Select the Build Phases tab.
Open Target Dependencies, and click the + button.
Locate the
Ensembles Resources iOS product, and add that as a dependency.
Open the Ensembles iOS.xcodeproj project in the source list, and open the Products group.
Drag the Ensembles.bundle product into the Copy
Bundle Resources build phase of your app.
Add the following import in your precompiled header file, or in any files using Ensembles.
It is step 10 that I am having problems with. Do I have to create a bridging header or just import the framework into my swift files ?
This is how I am importing within my CoreDataStack.swift file
import UIKit
import CoreData
import Ensembles
class CoreDataStack: NSObject, CDEPersistentStoreEnsembleDelegate {
}
This gives me the error;
No such module 'Ensembles'
I tried creating a bridging header by doing the following;
Add new header file
Import Ensembles
This is how that looks;
#ifndef Header_h
#define Header_h
#import <Ensembles/Ensembles.h>
#endif /* Header_h */
But still no luck, does anybody know where I am going wrong when trying to import the framework to use with my swift project ?
When creating a bridging header you do not need to use import.
However I don't think you may be adding a bridging header correctly, go to, file, new, file, add a objective-C file and a dialog should pop up asking if you want to create a bridging header. Add both files but delete the objective-C file and keep the bridging header.
Then import the ensembles framework to the bridging header like so.
#import <Ensembles/Ensembles.h>
When creating a bridging file successfully you should not need to import the framework in your swift files and it should be available throughout your project. See this post for more information - Connect Objective C framework to Swift iOS 8 app (Parse framework)
Usually I am using CocoaPods (with use_frameworks!) in order to manage my frameworks, but this PDF library (FastPdfKit) does not support CocoaPods, so i added it manually in "link binary with libraries" along with its dependencies. After that I let xcode create a bridging header for me (I created a .m file, and xcode created a bridging header automatically).
I imported the header in the bridging file like this #import <FastPdfKit/FastPdfKit.h>, but I can't acces any method/class from my swift files... (Use of undeclared type 'ReaderViewController' where ReaderViewController is a subclass of UIViewController in the framework).
I've also tried importing like this #import 'FastPdfKit.h" still gives the same errors.
To import Objective-C code into Swift from the same framework, go to Build Settings > Packaging and make sure the Defines Module setting for that framework target is set to “Yes”.
I have compiled a custom Objective-C Framework which I will be referring to as Custom.framework. I'm having an issue with the files inside the framework when I try to build the project the framework is linked in.
Inside Custom.framework I have my main Header file called Custom.h and the following code is where the problem arises:
#import <Foundation/Foundation.h> // 'Foundation/Foundation.h' file not found
I have a recursive framework and library path set up to where my .framework file is located: /Users/macbook/Library/Developer/Xcode/**
My project and framework files are in /Users/macbook/Sites/
Also my framework appears in red text, but is recognized when I import it if that helps.
As Glenn Howes states in a comment under the question, I needed to change the import to #import Foundation instead of using #import and turn on Enable Modules (C and Objective-C) in my build properties (which I already had).
Have you added Foundation.framework in Scheme --> Build Phases --> Link Binary With Libraries?
I added libsqlite3.0.dylib to my project, and then I tried to import using the following code:
import UIKit
import sqlite3
class Dataware: NSObject
{
}
But it's giving me this error:
No Such Module 'sqlite3'
Add it to your Bridging-Header.h file:
#import <sqlite3.h>
This is the primary mechanism for importing any C-language libraries.
If you don't yet have a Bridging-Header.h file:
Add a file Bridging-Header.h (or more typically (ProjectName)-Bridging-Header.h
Go to the build settings tab for your project
Find "Objective-C Bridging Header". The easiest way is to search for bridging.
Enter the name and path for the file you created in step one. It's probably (ProjectName)/(ProjectName)-Bridging-Header.h
when one want to add sqlite to framework target, module.map is needed
since sqlite is not mapped, and to do so just:
1. create file in your project 'module/module.map'
2. create the module from the umbrella header:
module sqlite3 [system] {
header "/Applications/Xcode6-Beta5.app/Contents/Developer/Platforms/iPhoneOS.platform/Developer/SDKs/iPhoneOS8.0.sdk/usr/include/sqlite3.h"
link "sqlite3"
export *
}
*change the Xcode6-Beta5.app in the path to right one
3. connect the map file to you project, search for 'import paths' in 'Build Settings'and put the full path to the module file
We need to import the header files for SQLite3 into the view controller so that the compiler can see the function and other definitions that make up the API.
There is no way to directly import the header file into Swift code, because the SQLite3 library is not packaged as a module.
The easiest way to deal with this is to add a bridging header to the project. Once you have a bridging header, you can add other header files to it, and those header files will be read by the Swift compiler. There are a couple of ways to add a bridging file. We’ll use the simpler of the two, which is to temporarily add an Objective-C class to the project. Let’s do that now.
File ➤ New ➤ File.... In the iOS section of the dialog, choose
Cocoa Touch Class and press Next. Name the class Temporary, make it a subclass of NSObject, change the language to Objective-C, and press Next. In the next screen, press the Create button.
When you do this, Xcode will pop up a window asking whether you want to create a bridging header. Press Yes.
Now, in the Project Navigator, you’ll see the files for the new class (Temporary.m and Temporary.h) and the bridging header, which is called SQLite Persistence-Bridging-Header.h. Delete the Temporary.m and Temporary.h files—you don’t need them anymore. Select the bridging header to open it in the editor, and then add the following line to it:
#import < sqlite3.h>
Now that the compiler can see the SQLite3 library and header files, we can write some more code in ViewController.swift
That's it!
Hi Please follow these steps
In xcode 8.3.3 using swift 3
Go to Build Phases tab
Go to Link Binary with Libraries sub tab.
(a) Click + button to add sqlite framework then search for sqlite then you can see libsqlite3.0.tbd and libsqlite3.tbd
(b) Then select only libsqlite3.tbd(Don't add both because the compiler can not find sqlite3 stuct when you declare in viewController)
Then Add Bridging-Header.h file (because sqlite is not written in swift)
Bridging name should be your Projectname-Bridging-Header.h file (Just for naming convention, not mandatory)
Write #import <sqlite3.h> in your Bridging-Header file
Go to build settings tab
(a) Under the build settings tab search for Swift Compiler - General option and set YES to Install Objective-C compatibility Header
(b) Set your name and path for the header file in Objective-C Bridging Header option (Or you can simply drag the bridging header file)