ios实现组件化具体步骤

905 阅读10分钟

ios实现组件化具体步骤

1. 创建主项目仓库,以及私有Pod源仓库

1.1 这里的主项目仓库指的是我们的项目工程仓库。这个为了演示CTMediator实现组件化,我们直接使用了作者的项目仓库 (功能就是简单的A页面push到B页面)

主工程仓库

1.2 github新建项目仓库

1.3 clone主项目仓库,并push到自己的主仓库上.

#执行命令 [推荐安装oh-my-zsh,有一些常用命令的记忆功能]
#cd到桌面(最好在桌面执行,不然多级文件夹,看着乱)
cd /Users/liguicheng/Desktop
# clone项目
git clone https://github.com/ModulizationDemo/MainProject
### clone完成后,需要先pod install,因为使用了作者的一个简单的布局库.
#####push到自己的项目仓库地址
#  查看所有远程仓库
git remote
# 删除之前的版本库
git remote rm origin
#增加新的地址
git remote add origin https://github.com/PhoenixLeeSin/MainProject
#提交
git add .
# 提交说明
git commit -m "第一次提交"
#提交(在存在从别的仓库克隆之后提交到另一个新的仓库的情况下(新仓库新建read.me)提交时会报错:提示:更新被拒绝,因为远程仓库包含您本地尚不存在的提交。这通常是因为另外
提示:一个仓库已向该引用进行了推送。再次推送前,您可能需要先整合远程变更
提示:(如 'git pull ...')。
提示:详见 'git push --help' 中的 'Note about fast-forwards' 小节。)
##针对上述问题 执行命令 之后正常执行git pull origin master命令即可
git push -u origin +master (也可以强制推入 git push -f origin master)

1.4 新建私有pod源仓库

# 这里的pod源仓库 指的是我们存放管理我们后面创建的组件的仓库。步骤同1.2  截图如下:

2. 新建组件项目和远端私有仓库,并同步。

这里的组件和主项目属于同一级别,只不过是我们的主项目需要使用这个组件,那么从具体的业务或者层级来说,组件属于子层级。

2.0 建立远端组件仓库

# 步骤同1.2相同,创建完成后,页面不用关,后面会用到。

2.1 桌面新建一个Xcode工程,这里使用命令

# cd到桌面
cd /Users/liguicheng/Desktop
# 在本地目录新建Xcode项目(在写这边文章时,A_Section已经创建,所有就用B_Section代替了)
pod lib create B_Section
##输入填入相关信息(根据实际情况填写)
What platform do you want to use?? [ iOS / macOS ]
 > ios

What language do you want to use?? [ Swift / ObjC ]
 > objc

Would you like to include a demo application with your library? [ Yes / No ]
 > yes

Which testing frameworks will you use? [ Specta / Kiwi / None ]
 > none

Would you like to do view based testing? [ Yes / No ]
 > no

What is your class prefix?
 > LS
#填写完成后 Xcode就会自动创建项目
#接下来可以删掉本地引用库里面的ReplaceMe.m文件,不删也不会报错.然后在项目中新建Classes文件夹,然后在项目中新建Classes文件夹,然后在项目中新建Classes文件夹

2.2 业务代码以及相关设置

2.2.1 上面我们提到在项目中新建classes文件,(新建的文件夹选择这个选项,不然在后面的podspec中找不到)!

2020-07-31更新:不知道是不是xcode的原因,新建的文件夹选项可以自己试一下,有的时候选择正常的 New Group也是可以的

2.2.2接下来就可以把MainProject中属于B组件的代码移动到这里了.

2.2.3 把主界面设置成BViewController

2.2.4 添加target

#import <Foundation/Foundation.h>

NS_ASSUME_NONNULL_BEGIN

@interface Target_B : NSObject
- (UIViewController *)Action_viewController:(NSDictionary *)params;
@end

NS_ASSUME_NONNULL_END



#import "Target_B.h"
#import "BViewController.h"
@implementation Target_B
- (UIViewController *)Action_viewController:(NSDictionary *)params {
    BViewController *viewController = [[BViewController alloc] init];
    return viewController;
}
@end
#添加完成后,可以验证一下BViewController.h/m 文件所属的位置是否正确
# cd 到工程目录
cd /Users/liguicheng/Desktop/B_Section
#查看树形结构
tree -L 5
#树状图部分(位置是正确的)
├── B_Section
│   ├── Assets
│   └── Classes
│       └── ReplaceMe.m
├── B_Section.podspec
├── Example
│   ├── B_Section
│   │   ├── B_Section-Info.plist
│   │   ├── B_Section-Prefix.pch
│   │   ├── Base.lproj
│   │   │   ├── LaunchScreen.storyboard
│   │   │   └── Main.storyboard
│   │   ├── Classes
│   │   │   └── BViewController
│   │   │       ├── BViewController.h
│   │   │       ├── BViewController.m
│   │   │       └── Target
│   │   │           ├── Target_B.h
│   │   │           └── Target_B.m
│   │   ├── Images.xcassets
│   │   │   └── AppIcon.appiconset
│   │   │       └── Contents.json
│   │   ├── LSAppDelegate.h
│   │   ├── LSAppDelegate.m
│   │   ├── LSViewController.h
│   │   ├── LSViewController.m
│   │   ├── en.lproj
│   │   │   └── InfoPlist.strings
│   │   └── main.m
│   ├── B_Section.xcodeproj
│   │   ├── project.pbxproj
│   │   ├── project.xcworkspace
│   │   │   └── contents.xcworkspacedata
│   │   └── xcshareddata
│   │       └── xcschemes
│   │           └── B_Section-Example.xcscheme

2.2.5 修改podfile,podspec等配置

#注释掉引用本地库

#BViewController中注释引用以及相关代码

#编辑podspec文件

#1 版本号一般是从0.0.1开始,当然这个并没有具体限制
#2 主页地址一般填写仓库地址(3)一致即可
#3 仓库地址使用https(http)开头的,不要使用SSH的
#4 组件代码位置。这个尤其需要注意,默认的模板中是:工程/Classes/**/* 我们把组件的代码放到了新建的文件夹下,那么需要修改此处,查看文件的位置直接把对应的父级文件夹拖入到终端就可以看到文件目录了(也可以使用tree来查看目录结构)

2.2.5 执行pod install 验证正确性

# cd 到工程目录下(podfile同一级下的Example下)
cd /Users/liguicheng/Desktop/B_Section/Example
# 执行操作
pod install

3. 新建组件B与外界联系媒介B_Category项目及远端仓库,并同步.

# 这一步操作和2中的操作是相同的,流程就是pod lib create B_Category来创建Xcode工程,podfile添加依赖库,添加分类,验证,因为涉及依赖,我们还是将不同的地方记录一下,来加深记忆和为后面的小伙伴脱坑。

3.1 创建远端仓库

#同步骤2.0 

3.2 本地新建xcode工程

#同2.1
pod lib create B_Category

3.3 podfile中添加 pod 'CTMediator'

#打开项目Podfile,添加
pod 'CTMediator'
#注释掉本地引用
#新建分类CTMediator+B.h
NS_ASSUME_NONNULL_BEGIN
#import <CTMediator/CTMediator.h>

@interface CTMediator (B)
- (UIViewController *)B_aViewController;
@end

NS_ASSUME_NONNULL_END

#import "CTMediator+B.h"

@implementation CTMediator (B)
- (UIViewController *)B_aViewController {
    return [self performTarget:@"B" action:@"viewController" params:nil shouldCacheTarget:NO];
}
@end

3.4 podspec编辑

#编辑同2.2.5步骤,注意s.source_files文件目录设置
Pod::Spec.new do |s|
  s.name             = 'B_Category'
  s.version          = '0.0.1'
  s.summary          = 'A short description of B_Category.'

  s.description      = <<-DESC
TODO: Add long description of the pod here.
                       DESC
  s.homepage         = 'https://github.com/PhoenixLeeSin/B_Category.git'
  s.license          = { :type => 'MIT', :file => 'LICENSE' }
  s.author           = { '350541732@qq.com' => 'leesin350541732@gmail.com' }
  s.source           = { :git => 'https://github.com/PhoenixLeeSin/B_Category.git', :tag => s.version.to_s }

  s.ios.deployment_target = '9.0'

  s.source_files = 'Example/B_Category/Classes/**/*'
  s.dependency 'CTMediator'
end

3.5 执行pod install

# cd到项目路径(和podspec同一层级)
 cd /Users/liguicheng/Desktop/B_Category/Example
# 执行pod install 
pod install

4 主项目Podfile本地引用组件B,并使项目编译通过.

4.1 把前面的2个项目文件copy到MainProject文件夹,并编辑MainProject项目的Podfile文件

4.2 编辑MainProject项目的Podfile文件

#注意这里引用本地组件库的路径,path的意思是相对于.podspec文件,指向的使我们的组件工程名称的路径,如果在4.1图中我们把组件B_Category和B_Section放在左侧总的工程文件夹下,那么我们引用的路径变成了path => '../B_Section'和path => '../B_Category'; 其中"../"指的是上一级。

4.3 运行pod install 验证并且修改主工程代码

#运行pod install 
pod install 
#成功后,此时主工程中在ViewController中还是直接引用的BViewController,组件化之后调用BViewController应该使用B_Category.
#因此在ViewController.m文件中做如下修改:
#import "CTMediator+B.h"
 (void)didTappedPushAViewControllerButton:(UIButton *)button
{
    UIViewController *viewController = [[CTMediator sharedInstance] B_aViewController];
    [self.navigationController pushViewController:viewController animated:YES];
}
#不清楚是不是版本问题,如果主工程中通组件代码中存在相同文件是会报错: ld: 2 duplicate symbols for architecture x86_64 注释掉就可以了

4.4 将本地引用改为远程引用,运行项目并编译成功,组件化完成.

4.4.1 将B_Section push到远端并打tag

# cd到B_Section
	cd /Users/liguicheng/Desktop/test/MainProject/B_Section
# 提交
	git add .
# 提交说明
  git commit -m "B_Section"
#设置远程仓库地址
	git remote add origin https://github.com/PhoenixLeeSin/B_Section.git
#push
	git push origin master
# 打tag tag值要和组件库版本号一直
 git tag 0.0.1
# 推上tag
git push --tags
###### 如果tag值写错了可以通过下面的命令删除
git tag -d 1.0.0
git push origin :1.0.0

4.4.2 本地验证.podspec文件

pod lib lint --allow-warnings

##验证通过大概如下
 -> B_Section
 -> B_Section (0.0.1)
    - WARN  | summary: The summary is not meaningful.
    - WARN  | url: The URL (https://github.com/PhoenixLeeSin/B_Section.git) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | xcodebuild:  note: Building targets in parallel
    - NOTE  | [iOS] xcodebuild:  note: Planning build
    - NOTE  | [iOS] xcodebuild:  note: Constructing build description
    - NOTE  | [iOS] xcodebuild:  warning: Skipping code signing because the target does not have an Info.plist file and one is not being generated automatically. (in target 'App' from project 'App')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'B_Section' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'Pods-App' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'App' from project 'App')
###如果不通过的话会报红

4.4.3 将B_Section.podspec文件提交到之前添加的本地私有索引库ConfigPrivatePod

# cd到组件的根目录下
cd /Users/liguicheng/Desktop/test/MainProject/B_Section
# 发布并验证
pod repo push ConfigPrivatePod B_Section.podspec --verbose --allow-warnings
##成功之后大概就是这个样子
  Testing with `xcodebuild`.
 -> B_Section (0.0.1)
    - WARN  | summary: The summary is not meaningful.
    - WARN  | url: The URL (https://github.com/PhoenixLeeSin/B_Section.git) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | xcodebuild:  note: Building targets in parallel
    - NOTE  | [iOS] xcodebuild:  note: Planning build
    - NOTE  | [iOS] xcodebuild:  note: Constructing build description
    - NOTE  | [iOS] xcodebuild:  warning: Skipping code signing because the target does not have an Info.plist file and one is not being generated automatically. (in target 'App' from project 'App')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'B_Section' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'Pods-App' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'App' from project 'App')

Updating the `ConfigPrivatePod' repo
  $ /usr/local/bin/git -C /Users/liguicheng/.cocoapods/repos/ConfigPrivatePod push origin master
  To github.com:PhoenixLeeSin/ConfigPrivatePod.git
     ec2f32c..61f38b5  master -> master
     
     # 发布时,如果组件本身引用了其他三方库 发布命令为:
     pod repo push YYYY XXXX.podspec --sources=私有库地址,https://github.com/CocoaPods/Specs.git --allow-warnings --use-libraries(包含.a库的情况) 
     或者
     pod repo push YYYY XXX.podspec --sources=http://10.254.3.56/iOS/GXPodsRepo,https://github.com/CocoaPods/Specs.git --allow-warnings --use-libraries --skip-import-validation --verbose

4.4.4 远程验证.podspec文件

pod spec lint --allow-warnings
###成功后信息
 -> B_Section (0.0.1)
    - WARN  | summary: The summary is not meaningful.
    - WARN  | url: The URL (https://github.com/PhoenixLeeSin/B_Section.git) is not reachable.
    - NOTE  | xcodebuild:  note: Using new build system
    - NOTE  | xcodebuild:  note: Building targets in parallel
    - NOTE  | [iOS] xcodebuild:  note: Planning build
    - NOTE  | [iOS] xcodebuild:  note: Constructing build description
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'B_Section' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'Pods-App' from project 'Pods')
    - NOTE  | [iOS] xcodebuild:  note: Execution policy exception registration failed and was skipped: Error Domain=NSPOSIXErrorDomain Code=1 "Operation not permitted" (in target 'App' from project 'App')
    - NOTE  | [iOS] xcodebuild:  warning: Skipping code signing because the target does not have an Info.plist file and one is not being generated automatically. (in target 'App' from project 'App')

Analyzed 1 podspec.

4.4.5 将B_Category按照以上相同的步骤执行操作(略)

4.5 修改本地引用为远端引用

#刚提交后如果存在以后错误信息
[!] Unable to find a specification for `B_Section`

You have either:
 * out-of-date source repos which you can update with `pod repo update` or with `pod install --repo-update`.
 * mistyped the name or version.
 * not added the source repo that hosts the Podspec to your Podfile.

Note: as of CocoaPods 1.0, `pod repo update` does not happen on `pod install` by default.
 #执行以下命令 更新一下即可
  pod install --repo-update
  
#最后成功后的工程  

4.6 常见错误信息解决

1 报错:Pods written in Swift can only be integrated as frameworks; add use_frameworks! to your Podfile or target to opt into using it. The Swift Pods being used are: ReactiveCocoa, ReactiveSwift, and Result
解决:在想应的pod 'ReactiveCocoa'下添加use_frameworks!
ps:注意use_frameworks!后面的!号
2 集成cocoapods的时候报错:'xxx' file not found with  include; use "quotes" instead
解决:引用路径的问题,更改引用路径。例如:#import <JSONModel.h>,改成#import <JSONModel/JSONModel.h> 就可以了
3 集成cocoapods的时候报错:include of non-modular header inside framework module 'XXX': 'XXX' [-Werror,-Wnon-modular-include-in-framework-module]
解决:引用路径的问题,更改引用路径。例如:#import "JSONModel.h",改成#import <JSONModel/JSONModel.h> 就可以了
4 集成cocoapods的时候报错:include of non-modular header inside framework module 'XXX': 'XXX' [-Werror,-Wnon-modular-include-in-framework-module]
解决:如果第3条解决不了,在pod spec lint后添加--use-libraries。同时在pod trunk push 或者pod repo push 【私有库】的后添加--use-libraries
--use-libraries表示使用静态库或者是framework,这里主要是解决当我们依赖一些framework库后校验提示找不到库的时候用到。
5 集成cocoapods的时候报错:Encountered an unknown error (Unable to find a specification for xxx depended upon by xxx
解决:在集成cocoapods的时候添加私有或者公有或者两者都有的sources。如公有的sources。pod repo push xiaofengCocoapodsRepo --sources=https://github.com/CocoaPods/Specs.git
```ruby