阅读视图

发现新文章,点击刷新页面。

Fastlane自动化打包到蒲公英

Fastlane

fastlane是一个旨在简化 Android 和 iOS 部署的开源平台,可以自动化开发和发布工作流程的各个方面。

一、安装Xcode命令行工具

fastlane 安装Xcode命令行工具:

xcode-select --install

Pasted Graphic.png 如果安装过会提示:

xcode-select: error: command line tools are already installed, 
use "Software Update" in System Settings to install updates

二、安装fastlane

提前配置好 HomeBrew 管理工具

brew install fastlane

查看 fastlane 版本:

fastlane -v
fastlane installation at path:
/usr/local/Cellar/fastlane/2.206.2/libexec/gems/fastlane-2.206.2/bin/fastlane
-----------------------------
[✔] 🚀
fastlane 2.206.2

将终端导航到项目目录并运行:

fastlane init

命令执行:

[✔] 🚀
[13:13:34]: Sending anonymous analytics information
[13:13:34]: Learn more at https://docs.fastlane.tools/#metrics
[13:13:34]: No personal or sensitive data is sent.
[13:13:34]: You can disable this by adding `opt_out_usage` at the top of your Fastfile
[✔] Looking for iOS and Android projects in current directory...
[13:13:34]: Created new folder './fastlane'.
[13:13:34]: Detected an iOS/macOS project in the current directory: 'FastlaneDemo.xcodeproj'
[13:13:34]: -----------------------------
[13:13:34]: --- Welcome to fastlane 🚀 ---
[13:13:34]: -----------------------------
[13:13:34]: fastlane can help you with all kinds of automation for your mobile app
[13:13:34]: We recommend automating one task first, and then gradually automating more over time
[13:13:34]: What would you like to use fastlane for?
1. 📸  Automate screenshots
2. 👩‍✈️  Automate beta distribution to TestFlight
3. 🚀  Automate App Store distribution
4. 🛠  Manual setup - manually setup your project to automate your tasks

[13:13:34]你想用快车道做什么?

  1. 📸自动截屏
  2. 👩✈️自动测试分发TestFlight
  3. 🚀自动化应用商店分销
  4. 🛠手动设置-手动设置您的项目自动化您的任务

这边选择 4

[14:29:49]: --- Setting up fastlane so you can manually configure it ---
[14:29:49]: ------------------------------------------------------------
[14:29:49]: Installing dependencies for you...
[14:29:49]: $ bundle update
[14:31:36]: --------------------------------------------------------
[14:31:36]: --- ✅  Successfully generated fastlane configuration ---
[14:31:36]: --------------------------------------------------------
[14:31:36]: Generated Fastfile at path `./fastlane/Fastfile`
[14:31:36]: Generated Appfile at path `./fastlane/Appfile`
[14:31:36]: Gemfile and Gemfile.lock at path `Gemfile`

项目里多了这三个文件:

Pasted Graphic 1.png

三、安装蒲公英插件

fastlane add_plugin pgyer

注册蒲公英,拿到 API KeyUser Key

1__#$!@%!#__Pasted Graphic.png

在上面看到的 fastlane 文件夹里面的 Fastfile 文件简单配置一下:

default_platform(:ios)

platform :ios do
desc "Description of what the lane does"
# 打包时候用的名称   例如 fastlane app
lane :develop do |options|
target = "FastlaneDemo"
configuration = "Debug"
gym(scheme: target, configuration: configuration, export_method:"development")
pgyer(api_key: "xxxxxxxxxx”)
end
end

终端运行:

fastlane develop

结果:

+------+------------------+-------------+
|           fastlane summary            |
+------+------------------+-------------+
| Step | Action           | Time (in s) |
+------+------------------+-------------+
| 1    | default_platform | 0           |
| 2    | gym              | 78          |
+------+------------------+-------------+

[17:39:32]: fastlane.tools finished successfully 🎉

可以看到上传蒲公英成功:

2__#$!@%!#__Pasted Graphic.png

点击应用信息:

Pasted Graphic 4.png

在项目本地也会生成一个ipa

Pasted Graphic 3.png

四、分发到Appstore

# 发布到appstore
  lane :to_appstore do

    # 先获取当前项目中的bundle version + 1
    @build_version = get_info_plist_value(path: "#{$info_plist_path}", key: "CFBundleVersion").to_i + 1

    # 针对于 iOS 项目开发证书和 Provision file 的下载工具
    sigh(
      force: true,
      output_path: "./fastlane/crets"
    )

    # 设置 bundle version
    set_info_plist_value(
      path: "./so/Supporting Files/so-Info.plist", 
      key: "CFBundleVersion", 
      value: "#{@build_version}"
    )

    # 针对于 iOS 编译打包生成 ipa 文件
    gym(
      workspace: "#{$project_name}.xcworkspace",
      scheme: "#{$project_name}",
      clean: true,
      configuration: "Release",
      export_method: "app-store",
      output_directory: "ipa_build/release",
      output_name: "#{$project_abbreviation}"
    )

    # 用于上传应用的二进制代码,应用截屏和元数据到 App Store
    deliver(
      force: true,# 上传之前是否成html报告
      submit_for_review: false,# 上传后自动提交审核
      automatic_release: true,# 通过审后自动发布
      skip_binary_upload: false,# 跳过上传二进制文件
      skip_screenshots: true,# 是否跳过上传截图
      skip_metadata: false,# 是否跳过元数据
    )
  end

运行:


[16:03:13]: $ bundle exec fastlane FastlaneDemo
[16:03:13]:
[16:03:13]: Get started using a Gemfile for fastlane https://docs.fastlane.tools/getting-started/ios/setup/#use-a-gemfile
+-----------------------+---------+--------+
|               Used plugins               |
+-----------------------+---------+--------+
| Plugin                | Version | Action |
+-----------------------+---------+--------+
| fastlane-plugin-pgyer | 0.2.4   | pgyer  |
+-----------------------+---------+--------+

[16:03:14]: ----------------------------------------
[16:03:14]: --- Step: Verifying fastlane version ---
[16:03:14]: ----------------------------------------
[16:03:14]: Your fastlane version 2.212.1 matches the minimum requirement of 2.68.2  ✅
[16:03:14]: ------------------------------
[16:03:14]: --- Step: default_platform ---
[16:03:14]: ------------------------------
[16:03:14]: Driving the lane 'ios FastlaneDemo' 🚀
[16:03:14]: ----------------------------------
[16:03:14]: --- Step: get_info_plist_value ---
[16:03:14]: ----------------------------------
[16:03:14]: ------------------
[16:03:14]: --- Step: sigh ---
[16:03:14]: ------------------

+-------------------------------------+-------+
|          Summary for sigh 2.212.1           |
+-------------------------------------+-------+
| force                               | true  |
| adhoc                               | false |
| developer_id                        | false |
| development                         | false |
| skip_install                        | false |
| include_mac_in_profiles             | false |
| ignore_profiles_with_different_name | false |
| skip_fetch_profiles                 | false |
| include_all_certificates            | false |
| skip_certificate_verification       | false |
| platform                            | ios   |
| readonly                            | false |
| fail_on_name_taken                  | false |
+-------------------------------------+-------+

[16:03:14]: To not be asked about this value, you can specify 
it using 'username'
[16:03:14]: Your Apple ID Username:

输入 Apple ID 去测试 ......

参考:

离屏渲染(二)

离屏渲染是在当前屏幕帧缓冲区外增加了一个临时新的缓冲区对将要进行显示的图片进行渲染操作再写回帧缓冲区,过个过程造成性能损耗。

离屏渲染(一)

离屏渲染是在当前屏幕帧缓冲区外增加了一个临时新的缓冲区对将要进行显示的图片进行渲染操作再写回帧缓冲区,过个过程造成性能损耗。

启动优化clang插桩(一)

启动优化clang插桩(一)

一、了解Clang

首先到Clang地址:Clang Documentation Pasted Graphic.pngPCs指的是CPU的寄存器,用来存储将要执行的下一条指令的地址,Tracing PCs就是跟踪CPU将要执行的代码。

二、如何使用

网页下拉有个Example Pasted Graphic 1.png 使用之前要在工程添加标记: Pasted Graphic 2.png

编译器就会在每一行代码的边缘插入这一段函数:__sanitizer_cov_trace_pc_guard(&guard_variable)

打开实例demo,在Build Settings 搜索 Other c Flag 填入 -fsanitize-coverage=trace-pc-guard

1__#$!@%!#__Pasted Graphic 1.png

项目会报未定义符号的错:

Pasted Graphic 7.png

这就需要去定义这两个符号,先把这两个函数复制过来:

Pasted Graphic 5.png 先把代码复制进ViewController

extern "C" void __sanitizer_cov_trace_pc_guard_init(uint32_t *start,
                                                    uint32_t *stop) {
  static uint64_t N;  // Counter for the guards.
  if (start == stop || *start) return;  // Initialize only once.
  printf("INIT: %p %p\n", start, stop);
  for (uint32_t *x = start; x < stop; x++)
    *x = ++N;  // Guards should start from 1.
}
// This callback is inserted by the compiler on every edge in the
// control flow (some optimizations apply).
// Typically, the compiler will emit the code like this:
//    if(*guard)
//      __sanitizer_cov_trace_pc_guard(guard);
// But for large functions it will emit a simple call:
//    __sanitizer_cov_trace_pc_guard(guard);
extern "C" void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
  if (!*guard) return;  // Duplicate the guard check.
  // If you set *guard to 0 this code will not be called again for this edge.
  // Now you can get the PC and do whatever you want:
  //   store it somewhere or symbolize it and print right away.
  // The values of `*guard` are as you set them in
  // __sanitizer_cov_trace_pc_guard_init and so you can make them consecutive
  // and use them to dereference an array or a bit vector.
  void *PC = __builtin_return_address(0);
  char PcDescr[1024];
  // This function is a part of the sanitizer run-time.
  // To use it, link with AddressSanitizer or other sanitizer.
  __sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));
  printf("guard: %p %x PC %s\n", guard, *guard, PcDescr);
}

把头文件也粘贴进来:

#include <stdint.h>
#include <stdio.h>
#include <sanitizer/coverage_interface.h>

两个方法里面都有extern “C”extern “C”的主要作用是为了能够正确实现C++去调用其他C语言的代码,加上extern “C”就会指示作用域内的代码按照C语言区编译,而不是C++,这个extern “C”在OC项目里没什么用,直接删除

此时还会包一个错误:

Pasted Graphic 8.png

这个__sanitizer_symbolize_pc(PC, "%p %F %L", PcDescr, sizeof(PcDescr));函数没有什么作用,直接删除即可。

三、代码调试

cmd + r运行,此时终端会打印一些信息:

Pasted Graphic 9.png

删除两个函数里面的注释,先注释第二个的内容,然后运行

INIT: 0x1025c5478 0x1025c54f0

这是运行打印得到的地址,就是函数(uint32_t *start, uint32_t *stop)startstop两个指针的地址

stop存储的就是我们工程里面符号的个数

for (uint32_t *x = start; x < stop; x++)
        *x = ++N;

看一下这个for循环,start会先复制给*xx++就是内存平移,按照uint32_t的大小去平移,而uint32_t的定义是typedef unsigned int uint32_t; 是无符号整型,占4个字节,所以每次按4个字节平移。

startstop里面存的是什么,打断点调试:

Pasted Graphic 10.png

先看start:

INIT: 0x1042a5278 0x1042a52e0
(lldb) x 0x1042a5278
0x1042a5278: 01 00 00 00 02 00 00 00 03 00 00 00 04 00 00 00  ................
0x1042a5288: 05 00 00 00 06 00 00 00 07 00 00 00 08 00 00 00  ................
(lldb)

由于uint32_t4个字节来存储发现start就是 0 1 2 3 4…,再看stop,由于stop的已经是结束位置,读取的数据是在startstop之间的数据,所以需要向前平移4个字节得到其真实数据。

(lldb) x (0x1042a52e0-4)
0x1042a52dc: 1a 00 00 00 00 00 00 00 00 00 00 00 fe f1 29 04  ..............).
0x1042a52ec: 01 00 00 00 00 00 00 00 00 00 00 00 90 40 2a 04  .............@*.
(lldb)

可以得到1a 就是26,也可以循环外面打印结果: Pasted Graphic 11.png 可以得到:

TraceDemo[16814:301325] 26

也是26个符号。

四、测试验证方法

可以验证一下,添加一个函数:

void test(void) {
    NSLog(@"%s",__func__);
}

符号变成27

TraceDemo[16911:304537] 27

再添加一个block

void (^block) (void) = ^{
    NSLog(@"%s",__func__);
};

符号变成28

TraceDemo[16933:305465] 28

添加一个数据类型属性:

@property (nonatomic ,assign) int age;

由于系统自动生成getter、setter方法,符号变成30

TraceDemo[16975:306816] 30

添加一个对象属性:

@property (nonatomic ,copy) NSString *str;

符号变成33

TraceDemo[17041:308780] 33

对象属性由于ARC,系统自动除了生成getter、setter方法外还生成了cxx_destruct()析构函数

添加一个方法:

- (void)test{
}

符号变成34

TraceDemo[17114:311256] 34

在其他类AppDelegate类中添加一个属性:

@interface AppDelegate : UIResponder <UIApplicationDelegate>
@property (nonatomic, strong) NSString *name;
@end

符号变成37:

TraceDemo[17266:316294] 37

符号变成37

结论

这就说明了通过这个方法整个项目里的符号,它都能捕获到。

❌