Osheep

时光不回头,当下最重要。

手册1:Ruby生成Objective-C代码及应用

导语:在iOS开发中,使用脚本语言(一般选择Ruby或Python)提高工作效率,本文介绍如何使用Ruby生成Objective-C代码及其在项目中的应用。

一、概述

  • 使用Ruby生成简单的Objective-C代码,这件工作并不复杂;

  • 先介绍Xcode自动运行脚本相关设置自动添加类文件到项目

  • 再介绍一个使用Ruby生成Objective-C代码的实例

  • 最后,介绍使用Ruby生成Objective-C代码在项目中的应用

    说明:当然也可以选择使用Python语言,生成Objective-C代码。(选择使用哪种语言并不重要)

二、Xcode自动运行脚本

目标:在运行项目时自动运行脚本。考虑到可能在项目中引入比较多的脚本,建议在项目的根路径下新建一个存放脚本的文件夹;在这个文件夹中,集中管理脚本。推荐两个比较常见的设置自动运行脚本的办法。

方法1:External Build System(外部编译系统)

具体步骤分为以下 5 步

1)新建External Build System

在工程下添加一个target:选择Cross-platform > Other > External Build System,取名为CodeGenerator,结果如下

《手册1:Ruby生成Objective-C代码及应用》

新建External Build System.png
2)新建shell脚本文件

在工程的根路径下新建一个ToolScripts文件夹,新建脚本文件,名为start.sh,结果如下:

《手册1:Ruby生成Objective-C代码及应用》

shell脚本位置.png
3)设置CodeGenerator

选择Targets > CodeGenerator >Info > External Build Tool Configuration,设置如下:

《手册1:Ruby生成Objective-C代码及应用》

设置CodeGenerator.png

说明Build Tools中填入start.sh所在的路径;Directory中填入存放所有脚本的文件夹,本例中是ToolScripts所在的位置。如果编译失败,请检查这里Directory的设置,修改成对应的位置。

4)添加运行依赖

选择Targets > QSRunScriptDemo > Build Phase > Target Dependencies,添加运行依赖,示意图如下:

《手册1:Ruby生成Objective-C代码及应用》

添加运行依赖.png
5)编译运行

编译运行,选择Show the report navigator -> build,可以看到对应的日志输出

《手册1:Ruby生成Objective-C代码及应用》

脚本输出内容.png
方法2:项目中直接添加脚本执行

具体步骤分为以下 4 步

1)新建shell脚本文件

在工程的根路径下新建一个ToolScripts文件夹,新建脚本文件,名为start.sh,这步骤和方法1一样。

2)添加Run Script

选择Targets > QSRunScriptDemo > Build Phase中添加 New Run Script Phase 即可,示意图如下:

《手册1:Ruby生成Objective-C代码及应用》

添加Run Script.png
3)设置Run Script

在Run Script中设置执行start.sh命令即可。

《手册1:Ruby生成Objective-C代码及应用》

设置Run Script.png
4)编译运行

编译运行,选择Show the report navigator -> build,可以看到对应的日志输出

《手册1:Ruby生成Objective-C代码及应用》

脚本输出内容.png
3、小结
  • 我们并没有直接设置执行Ruby 或 Python 代码,是因为这两类脚本可能并存在项目中,编译前执行shell脚本,在shell脚本中定义执行Ruby 或 Python脚本。

  • 接下来介绍如何将生成的类文件自动添加到项目中。

三、自动添加类文件到项目

目标:将通过Ruby 脚本来生成类文件自动添加到项目。(手动添加也可以,但是我想偷点懒)

1、准备工作
  • 在Xcode项目中,我们手动添加和删除类文件,其实是在修改project.pbxproj文件。

  • Cocoapods提供了一个可以创建和修改 Xcode 工程文件的工具:Xcodeproj,该工具中有Ruby 的开源库xcodeproj,可以帮助我们实现自动添加类文件到项目。(Cocoapods也是通过它自动添加文件到到项目)

  • 我们可以通过安装Cocoapods实现安装ruby的xcodeproj库;当然也可以直接安装,执行命令gem install xcodeproj即可。无论是选择哪种方案,都需要注意使用正确的ruby源。

  • 因为一直在使用Cocoapods,恰好在升级系统到macOS 10.13后,发现使用xcodeproj库有问题,原因是Cocoapods版本过旧,需要升级Cocoapods,升级过程中,要注意现在“taobao Gems 源已停止维护”,使用 ruby-china 提供镜像服务。下面以安装Cocoapods为例:

    sudo gem update --system    //升级gem,很有必要
    
    gem sources --remove https://rubygems.org/
    gem sources --remove https://ruby.taobao.org/       //如果安装了淘宝的镜像
    gem sources -a https://gems.ruby-china.org/          //保证只使用ruby-china镜像
    gem sources -l                                       //查看更换源结果,保证只有ruby-china镜像
    
    sudo gem uninstall cocoapods                           //如果有旧的CocoaPods,先卸载
    sudo gem install -n /usr/local/bin cocoapods          //安装最新的
    
2、主要代码实现
#添加类文件到项目
def add_files_to_projects(oc_file_paths,group_path)

  #1、获取.xcodeproj
  xcodeproj_path = File.expand_path File.join(__dir__, "../", "QSRunScriptDemo.xcodeproj")
  project = Xcodeproj::Project.open(xcodeproj_path)

  #2、获取target
  target = project.targets.first

  #3、创建group
  generator_group = project.main_group.find_subpath(group_path, true)
  generator_group.clear
  generator_group.set_source_tree('SOURCE_ROOT')

  #4、向group中添加文件
  file_refs = []
  oc_file_paths.each do |f|
      unless generator_group.find_file_by_path(f)
          file_ref = generator_group.new_reference(f)
          file_refs << file_ref
      end
  end
  #5、将文件加入 Build Phases
  target.add_file_references(file_refs)

  #6、保存 project
  project.save

end

四、Ruby生成Objective-C代码实例

1、输入:txt模板(文件名user_model.txt)
varchar,name
int,age
varchar,address
varchar,password

说明:文件名和OC类名相关,文本内每一行描述属性类型和名称。

2、执行脚本(自动执行)

在start.sh文件中输入执行脚本命令

 ruby generator_model/model_generator.rb
3、输出:OC类文件及代码
// QSUserModel.h文件
// Generated by Ruby.  DO NOT EDIT!
//  Copyright © 2017年 shaoqing. All rights reserved.

#import <UIKit/UIKit.h>

@interface QSUserModel : NSObject

@property (nonatomic,copy)NSString *name;
@property (nonatomic,assign)NSInteger age;
@property (nonatomic,copy)NSString *address;
@property (nonatomic,copy)NSString *password;

@end

//QSUserModel.m文件
// Generated by Ruby.  DO NOT EDIT!
//  Copyright © 2017年 shaoqing. All rights reserved.

#import "QSUserModel.h"
@implementation QSUserModel

@end

说明:类名QSUserModel,根据模板文件名而来;属性定义根据模板内容而来。

3、效果

1)运行项目前的文件夹和工程目录显示如下

《手册1:Ruby生成Objective-C代码及应用》

文件夹.png
《手册1:Ruby生成Objective-C代码及应用》

工程目录.png

2)运行项目后,自动执行脚本后的文件夹和工程目录显示如下

《手册1:Ruby生成Objective-C代码及应用》

文件夹.png
《手册1:Ruby生成Objective-C代码及应用》

工程目录.png

说明1:通过ruby脚本,实现了根据模板实现了自动生成Model类自动添加文件到项目,详细代码请参考QSRunScriptDemo

说明2:本例只是一个简单例子,主要为了说清思路,设计比较粗糙;在实际工程中,模板中需要定义的信息很多,txt并不是一个很好的选择;ruby脚本还需要更多完善的地方。

四、项目中的应用

1、概述
  • 在项目中使用脚本生成代码这件事,其目标在规范保持一致性减少重复工作量减少错误;尤其在跨团队、跨部门的协作工作中,这种规范和一致性尤为重要。

  • 下面介绍项目中的两个使用场景。

2、前后端数据联调

问题描述

  • 在某版本的开发过程中,因业务临时调整,后台在代码中变动了数据结构或数据字段名;

  • 后台因为代码重构,修改了数据结构或数据字段名;

  • 发生以上情况时,如果后台没有及时通知客户端,或者仅告知Android,没有告知iOS同学,或者客户端同学没有及时作出响应,无论哪种情况,出bug或Crash的可能性都比较高。

处理办法

  • 前后端协商,定义一个模板,模板中描述数据联调的相关数据结构信息,如字段名和字段值类型等,客户端根据脚本自动生成对应的Objective-C或Java代码。一旦后台要修改了数据结构,先强制修改模板,一旦有变动,iOS和Android生成的Model类代码会有变动,比较大的变动,如删除字段,会导致编译错误,能更好让大家发现问题,及时修改。
3、事件上报

问题描述

  • 每个版本产品同学都会新增事件上报、或定期清理无效的上报事件,或不定期地更新上报事件的参数。

  • 一旦这些变动(删除事件、更新上报事件的参数)没有周知客户端同学,上报就会出现数据不全、遗漏上报或客户端无用的上报代码越来越多。

  • 更麻烦的是,在某一版本(一般是重要的大版本)要处理好之前产品变动上报事造成的问题;产品需要重新整理上报事件,开发需要删除、修改和新增上报代码,测试需要回归测试(上千个上报事件的量足可以大家忙地很happy)

  • 当然,也有可能开发人员上报错误参数。

处理办法

  • 我们定义一个模板,模板中描述事件上报需要的信息,如事件ID、事件参数等,产品一旦要变更统计事件,先强制要求产品修改模板,客户端根据模板自动生成对应的Objective-C或Java代码,一旦事件上报有修改,生成的代码会有变化,比较大的变动,如新增或删除上报参数,会导致编译错误,能更好让大家发现问题,及时修改。

  • 此外,我们还在生成参数检验的代码,更好地提醒开发注意上报的参数值正确与否。

4、小结

在iOS项目中,脚本生成代码这类做法,不单单是帮助iOS开发减少重复工作量,从更广的范围来看,其实是为了让跨团队,跨部门的合作更加高效,更好地达成目标。

End

点赞