简体   繁体   中英

The 'Pods-App' target has transitive dependencies that include static binaries when using GTM in a swift framework

I'm trying to rework a part of a swift 3 project to make it a swift framework in order to use it as a pod. The thing is that I need to use GoogleTagManager legacy (v3) as a dependency and I get the following error when doing pod spec lint :

ERROR | [iOS] unknown: Encountered an unknown error (The 'Pods-App' target has transitive dependencies that include static binaries: (/private/var/folders/7t/0cd0n1gn46xd7r1cywrgcy2w0000gn/T/CocoaPods/Lint/Pods/GoogleTagManager/Libraries/libTagManager.a)) during validation.

Or, with GTM v5 :

ERROR | [iOS] unknown: Encountered an unknown error (The 'Pods-App' target has transitive dependencies that include static binaries: (/private/var/folders/7t/0cd0n1gn46xd7r1cywrgcy2w0000gn/T/CocoaPods/Lint/Pods/GoogleTagManager/Frameworks/GoogleTagManager.framework)) during validation.

I'm using the latest cocoapods version (1.1.0.rc.2) and, for what I understood, the problem comes from the dependencies of the GTM pod, which at least one is a static library.

I read some threads where people talk about workarounds to install static libraries within a framework, or to wrap static libraries into a framework when creating a pod. The thing is that the static library is a dependancy of the GTM pod, so I have no control over it. At least that's what I understood in here .

Here is my Podfile :

# Uncomment this line to define a global platform for your project
platform :ios, '8.0'

target 'MyProject' do
  # Comment this line if you're not using Swift and don't want to use dynamic frameworks
  # use_frameworks!

  # Pods for MyProject
    pod 'GoogleTagManager', '~> 3.15.2'
end

and here is my (shortened for StackOverflow) MyProject.podspec :

Pod::Spec.new do |s|

  s.name         = "MyProject"
  s.version      = "0.1.0"

  s.platform = :ios, '8.0'
  s.ios.deployment_target = '8.0'

  s.source_files  = "MyProject", "MyProject/**/*.{h,m}", "MyProject/**/*.{swift}"
  s.dependency 'GoogleTagManager', '~> 5.0.0'

end

I already tried to download the GTM SDK and install it without cocoapods, but I guess I missed a step because I couldn't make it work.

So I'd like some advices on my podspec and podfile files, or an explaination on how to install the SDK without cocoapods. Thanks a lot !

Well, after months I had to come back to this project. Since the GTM pod hasn't change and still has static libraries as dependencies, it is still impossible to create a framework that has the GTM pod as dependency and to distribute it through Cocoapods.

I eventually decided to ignore Cocoapods and to manually add the third party frameworks to mine. So this answer won't match perfectly my question but it is the only way I found to ditribute my framework.

So, the first step is to create a new project. Select Cocoa Touch Framework :

选择可可触摸框架

Give it a name, mine will be myFramework . Once your workplace is ready, add a new target to it :

如何添加新目标

Click on the cross platform tab and select the Aggregate template. I'll name mine Aggregate (so much originality). But we won't care too much about it for now.

总目标

Once you have done that, your workplace is set for you to create your amazing framework ! Let's dive a bit further !

You're gonna now create or copy your source files. If you copy them, don't forget to check the box Copy items if needed and be sure that they are added to the framework target :

在复制文件时验证选项

Until now, no big surprise I guess.

Since my question was about GTM, that's the framework we're gonna add as a dependency for our framework. I couldn't find the source elsewhere that on Cocoapods, so I created a new project (I used the application template and named it PodApp ), then I added Cocoapods to it. Open your terminal and navigate into the PodApp project folder :

  1. pod init
  2. vi Podfile
  3. Under #Pods for PodApp , add pod 'GoogleTagManager', '~> 6.0.0'
  4. Save and close the Podfile, and run pod install
  5. Once the dependency is downloaded and installed, close the PodApp project window and run open PodApp.xcworkspace

In your Framework project, add a new new Group you'll name Frameworks (right click in the Xcode Navigator -> new Group). You're gonna copy all the dependencies Cocoapods downloaded in the PodApp project under the Frameworks group of myFramework . Once again, dont forget to add it to myFramework target and to copy items if needed as seen above.

在您的项目中拖放框架

On the below image, click on 1 , 2 , 3 , if everything went well, you should see the frameworks/libs you just added on 4 .

xcode项目

For Firebase to work well, you'll also have to link with AdSupport.framework. Simply click on the + ( 5 ), search for it, and add it.

I had some troubles with GoogleToolBoxForMac too, what I had to do was to build the PodApp project, and to copy the GoogleToolBoxForMac.framework under PodApp /Pods/Products/ in the group myFramework /Frameworks/. Remember to add it to the correct target and to copy the item .

Another tricky detail related to GTM : you have to add some resources to your framework. Follow the step on the next image :

在此处输入图片说明

On the popup that opens, click on Add Other and find where you saved the GTM.framework, expand it and add the TagManagerResources.bundle (don't forget to copy the item !).

TagManagerResources.bundle

Since the other resources may give you warnings (in this specific example), you can delete them with the - .

If you want the final user of your framework to be able to use the frameworks that yours embeds, right above the "Copy Bundle Resources", open the "Headers" panel, drag and drop all the project headers to public .

All these frameworks can now be accessed by your own framework, but to make them available, you have to import their headers in your myFramework.h :

#import <myFramework/AnObjectiveCClass.h>

#import <GoogleTagManager/GoogleTagManager.h>
#import <GoogleTagManager/TAGCustomFunction.h>

#import <myFramework/GTMDefines.h>
#import <myFramework/GTMNSData+zlib.h>

#import <FirebaseCore/FirebaseCore.h>
#import <FirebaseAnalytics/FirebaseAnalytics.h>
#import <FirebaseInstanceID/FirebaseInstanceID.h>

#import <myFramework/GAI.h>
#import <myFramework/GAIDictionaryBuilder.h>
#import <myFramework/GAIEcommerceFields.h>
#import <myFramework/GAIEcommerceProduct.h>
#import <myFramework/GAIEcommerceProductAction.h>
#import <myFramework/GAIEcommercePromotion.h>
#import <myFramework/GAIFields.h>
#import <myFramework/GAILogger.h>
#import <myFramework/GAITrackedViewController.h>
#import <myFramework/GAITracker.h>

#import <myFramework/pb_encode.h>
#import <myFramework/pb.h>
#import <myFramework/pb_decode.h>
#import <myFramework/pb_common.h>

Alright, we're almost done !

项目信息/构建设置

Now, select the Info section of your project ( 1 in the image above), check the version you're building for (mine is 8.0 for backward compatibility with most devices). Under the Configurations panel, remove the Debug by selecting it, and pressing the - . Now select Build Settings ( 2 on the image), we're gonna make some changes in here.

  • Build Active Architecture Only : No
  • Allow Non-modular Includes In Framework Modules : No
  • Valid Architectures : arm64 armv7 i386 x86_64 (since armv7s doesn't build for some frameworks in this example)
  • Preprocessor Macros : PB_NO_PACKED_STRUCTS=1 PB_FIELD_32BIT=1
  • Enable Modules (C and Objective-C) : Yes

In your two targets, for the mentioned Build Settings, set them to $(inherited) , it means that they will inherit from the parameters you just set on the Project Build Settings.

In the framework target, I also set the Other Linker Flags as what was set in the PodApp project, but I'm not 100% sure it is necessary.

(FYI, here they are : $(inherited) -ObjC -l"GoogleAnalytics" -l"c++" -l"sqlite3" -l"z" -framework "AdSupport" -framework "CoreTelephony" -framework "FirebaseAnalytics" -framework "FirebaseCore" -framework "FirebaseInstanceID" -framework "GoogleSymbolUtilities" -framework "GoogleTagManager" -framework "GoogleToolboxForMac" -framework "GoogleUtilities" -framework "JavaScriptCore" -framework "SystemConfiguration" -framework "StoreKit" -framework "AddressBook" -framework "CoreData" )

Set Define Modules to yes .

Now select the Aggregate target, which will create a fat framework, a file containing several versions of our framework, one for each architecture we specified a few steps ago ( arm64 armv7 i386 x86_64 ). We will have to tell Xcode what we want it to build. Follow the steps of the below image ( 1 ) :

图片说明

In the Build Phases, you want your Aggregate target to build the myFramework.framework before being built itself.

Once the myFramework.framework is added, press the + annotated as 2 in the picture, and select New Run Script Phase . Paste the following script in it :

# Merge Script

# 1
# Set bash script to exit immediately if any commands fail.
set -e

# 2
# Setup some constants for use later on.
FRAMEWORK_NAME="myFramework"

# 3
# If remnants from a previous build exist, delete them.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

# 4
# Build the framework for device and for simulator (using
# all needed architectures).
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch arm64 -arch armv7 -arch armv7s only_active_arch=no defines_module=yes -sdk "iphoneos"
xcodebuild -target "${FRAMEWORK_NAME}" -configuration Release -arch x86_64 -arch i386 only_active_arch=no defines_module=yes -sdk "iphonesimulator"

# 5
# Remove .framework file if exists from previous run.
if [ -d "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework" ]; then
rm -rf "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework"
fi

# 6
# Copy the device version of framework to Framework directory.
cp -r "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework" "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework"

# 7
# Replace the framework executable within the framework with
# a new version created by merging the device and simulator
# frameworks' executables with lipo.
lipo -create -output "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphoneos/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}" "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/${FRAMEWORK_NAME}"

# 8
# Copy the Swift module mappings for the simulator into the
# framework.  The device mappings already exist from step 6.
cp -r "${SRCROOT}/build/Release-iphonesimulator/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule/" "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework/Modules/${FRAMEWORK_NAME}.swiftmodule"

# 9
# Delete the most recent build.
if [ -d "${SRCROOT}/build" ]; then
rm -rf "${SRCROOT}/build"
fi

# 10
# Remove .zip file if exists from previous run.
if [ -d "${PROJECT_DIR}/${FRAMEWORK_NAME}.zip" ]; then
rm -rf "${PROJECT_DIR}/${FRAMEWORK_NAME}.zip"
fi

# 11
# Zip the Framework and License all together.
zip -r "${PROJECT_DIR}/${FRAMEWORK_NAME}.zip" "${PROJECT_DIR}/LICENSE" "${PROJECT_DIR}/${FRAMEWORK_NAME}.framework"

On the script's step 2, change the name with your framework's name. Take time to understand what it does, and change its behavior if it doesn't meet your requirements. What it does in the end is that it creates a framework and an zip archive in your project's folder. I did that to link it with each of the Github release.

Everything should work fine now. Select Aggregate as the active Scheme, and run it.

运行汇总方案

If you want to add your framework in a test application, create a new Application project, simply drag and drop your myFramework.framework ( from your myFramework folder for example ) to your Application project. Once again, don't forget to add it to the correct target, and to copy the items. In your Application target, under the General tab, add your framework in the Embedded Binaries panel, but delete it once from the Linked Frameworks and Libraries panel since it should be there twice (check it out before doing it). Import your framework

import myFramework

and start using what you built !

NB : if you're trying with GTM, do not forget to add the stuff related to a GTM integration (your container and the GoogleInfo plist):

GTM相关资料

I really hope this will help you ! Do not hesitate to comment if anything isn't clear or if you meet a problem, I'll do my best to help you.

Please find my sources below :

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM