I am trying to build a framework that makes use of the geopackage-ios CocoaPods dependency. I would then like to statically embed this framework into one or more apps.
Similar questions have been asked before, but I couldn't find a solution to my problem. Here's what I've been trying so far:
First Approach: Building Manually
In this approach, I would create a static library using Xcode, add the CocoaPods dependencies to it and build it. The problem with this approach, however, is that the resulting framework will not have the CocoaPods dependencies embedded into it.
- Create a new static library from Xcode (File > New > Project… > iOS: Static Library) named "MyLibrary" with language Swift.
- Create a
Podfilein the project root directory with the following content:
target 'MyLibrary' do
pod 'geopackage-ios', '~> 7.2.1'
end
- Run
pod install. (This will install thegeopackage-iospod and 10 depending pods.) - Open the newly created
MyLibrary.xcworkspaceand add aBridgingHeader.hto the "MyLibrary" group having the following content:
#ifndef BridgingHeader_h
#define BridgingHeader_h
#import "geopackage-ios-Bridging-Header.h"
#endif
- Reference the bridging header by clicking on the "MyLibrary" project in the project navigator, selecting the "MyLibrary" target and, in the Build Settings, specifying
MyLibrary/BridgingHeader.has the "Objective-C Bridging Header". - Modify
MyLibrary.swiftto use the GeoPackage dependency:
public class MyLibrary {
public init() {}
public func test() {
let manager = GPKGGeoPackageFactory.manager()!
print("Manager:", manager)
}
}
- Build the library for the iOS simulator by pressing
Cmd + B. - Optionally, create a static framework using a shell script like the one in this article (which will compile the library once for the simulator and once for physical devices and then combine the two results to a universal framework using the
lipocommand).
When I embed either the static library (along with the MyLibrary.swiftmodule) or the universal framework into an app, linking will fail for this app:
Undefined symbols for architecture x86_64:
"_OBJC_CLASS_$_GPKGGeoPackageManager", referenced from:
objc-class-ref in libMyLibrary.a(MyLibrary.o)
"_OBJC_CLASS_$_GPKGGeoPackageFactory", referenced from:
objc-class-ref in libMyLibrary.a(MyLibrary.o)
ld: symbol(s) not found for architecture x86_64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
I could also add the geopackage_ios.framework (found in the build folder of "MyLibrary") to the app (making sure to choose the Embed & Sign embedding option), which will allow the app to be built successfully. Then, however, the app will crash upon launch:
dyld[79209]: Library not loaded: @rpath/ogc_api_features_json_ios.framework/ogc_api_features_json_ios
Referenced from: /Users/admin1/Library/Developer/CoreSimulator/Devices/C3D61224-CFE8-45CC-951B-7B6AB54BC8B3/data/Containers/Bundle/Application/D41A82D6-4E69-4BB6-AC59-6BC28AE58795/TestApp.app/Frameworks/geopackage_ios.framework/geopackage_ios
One might be able to fix this by adding all eleven pod frameworks to the app, which, however, is what I'm trying to avoid.
Second Approach: Using PodBuilder
A second approach would be to use PodBuilder, which aims at automating this particular kind of build task. This approach, however, fails with a build error, the cause of which I can't quite make out.
- Again, I would start out with a new Xcode project. This time, I'd create an iOS Swift app named "MyApp".
- I would create a
Podfilewith almost the same content as above:
use_frameworks!
target 'MyApp' do
pod 'geopackage-ios', '~> 7.2.1'
end
- Then, I'd run
pod install. - Next, I would install PodBuilder, create an empty Git repository (which PodBuilder requires for some reason), initialize PodBuilder, and start the build task:
sudo gem install pod-builder
git init
pod_builder init
pod_builder build geopackage-ios
- The build will fail, however, with errors like these written to
/tmp/pod_builder/pod_builder.err:
Undefined symbols for architecture arm64:
"_PROJ_WEB_MERCATOR_MAX_LAT_RANGE", referenced from:
+[GPKGTileBoundingBoxUtils toWebMercatorWithBoundingBox:] in GPKGTileBoundingBoxUtils.o
+[GPKGTileBoundingBoxUtils boundDegreesBoundingBoxWithWebMercatorLimits:] in GPKGTileBoundingBoxUtils.o
-[GPKGTileDao isXYZTiles] in GPKGTileDao.o
-[GPKGTileGenerator adjustXYZBounds] in GPKGTileGenerator.o
"_PROJ_UNDEFINED_CARTESIAN", referenced from:
-[GPKGSpatialReferenceSystemDao createIfNeededWithSrs:andOrganization:andCoordsysId:] in GPKGSpatialReferenceSystemDao.o
"_PROJ_AUTHORITY_NONE", referenced from:
-[GPKGSpatialReferenceSystemDao createIfNeededWithSrs:andOrganization:andCoordsysId:] in GPKGSpatialReferenceSystemDao.o
[…]
- This seems to be a problem with the
geopackage-iospod itself, which can be fixed by cloning our own version of the repo …
cd ..
git clone --branch 7.2.1 https://github.com/ngageoint/geopackage-ios.git
- …, installing the pods …
cd geopackage-ios
pod install
- … manually copying the
proj-iossource files …
cp -r Pods/proj-ios/proj-ios geopackage-ios
…, and opening the
geopackage-ios.xcodeprojto reference theproj-iosfiles in thegeopackage-iosgroup inside that project.Then telling CocoaPods to use our local version of the pod …
use_frameworks!
target 'MyApp' do
pod 'geopackage-ios', :path => '../geopackage-ios'
end
- …, reinitializing PodBuilder …
cd ../MyApp
pod_builder deintegrate
pod deintegrate
pod install
pod_builder init
- … and allowing PodBuilder to use local pods by editing the
./PodBuilder/PodBuilder.jsonfile:
{
…,
"allow_building_development_pods": true,
…
}
- Then, one can try to rebuild:
pod_builder build geopackage-ios
This time, the build will fail with a different error:
The following build commands failed:
CompileC /tmp/pod_builder/build/Pods.build/Release-iphoneos/sf-proj-ios.build/Objects-normal/arm64/SFPGeometryTransform.o /tmp/pod_builder/Pods/sf-proj-ios/sf-proj-ios/SFPGeometryTransform.m normal arm64 objective-c com.apple.compilers.llvm.clang.1_0.compiler (in target 'sf-proj-ios' from project 'Pods')
(1 failure)
The SFPGeometryTransform.m file, however, looks fine.
The full build log is available here.
Third Approach: Using Rome
The third approach would be to use cocoapods-rome.
- To use it, one would install Rome …
sudo gem install cocoapods-rome
- …, get rid of the PodBuilder stuff …
pod_builder deintegrate
pod deintegrate
- …, quickly adjust the
Podfile:
use_frameworks!
platform :ios, '13.0'
plugin 'cocoapods-rome', { :pre_compile => Proc.new { |installer|
installer.pods_project.targets.each do |target|
target.build_configurations.each do |config|
config.build_settings['SWIFT_VERSION'] = '5.0'
end
end
installer.pods_project.save
},
dsym: false,
configuration: 'Release'
}
target 'MyApp' do
pod 'geopackage-ios', :path => '../geopackage-ios'
end
- … and install the pods:
pod install
This, however, will fail with the exact same error as PodBuilder.
Can anyone give me some advice on any of these approaches? Or does anyone perhaps have a whole different idea on how to build such a framework?
(EDIT: It seems like the PROJProjectionTransform.h file imported to SFPGeometryTransform.m cannot be found. Anyway, I don't think these approaches are expedient. So any help is highly appreciated.)