macOS下苹果手机刷机

苹果手机在大版本升级之后也会变得卡卡的,可以通过下载官方的固件包来刷机,这样可以让手机变得更流畅。

# 下载官方镜像

首先我们需要下载官方的固件包,如果你有苹果开发者帐号,可以在Software Downloads (opens new window)下载,如果没有帐号可以在 ipsw.me (opens new window) 上找到对应的固件包。我的手机是 iPhone SE (2nd generation),所以我下载的固件包名字是iPhone12,8_17.1.1_21B91_Restore.ipsw

# 手机连接 Mac 系统

MacOS 在版本 12 以上的系统中,已经不支持使用 iTunes 来管理手机了,所以我们需要使用 Finder 来管理手机。我们连接手机到 Mac 系统,这时候会弹出一个提示框,我们需要点击信任按钮。

# 开始刷机

在 Finder 中可以看到我们连接的手机了,我们可以点击手机的名字,然后在右侧的窗口中点击 Restore iPhone... 按钮。需要注意的是,点击 Restore iPhone 按钮之前,需要按住 Option 键,这样才会弹出选择固件包的窗口。选择我们刚刚下载好的固件,就开始刷机了。刷机完成之后,系统会有弹窗提示,这时候我们断开手机和电脑的连接,手机就可以正常使用了。

# 总结

苹果的刷机比安卓简单很多,但是苹果的手机刷机是不能降级的,所以需要注意固件的版本。

# 参考

苹果 iPhone / iPad 刷机教程 (opens new window)

尝鲜派 (opens new window)

macOS下编译C++文件

WebAssembly 是一种新的编译目标,可以将 C/C++ 等语言编译成 WebAssembly,然后在浏览器中运行。我最近在研究如何把zbar (opens new window)编译成 WebAssembly,然后在浏览器中使用。第一步就是想把官方的例子编译成二进制测试下代码,但是在 MacOS 下编译的时候遇到了一些问题,这里记录下。

# 官方例子

scan_image.cpp (opens new window)

官方提供了一个例子,可以用来测试二维码识别功能,这个例子有两个依赖 Magick++.h 和 zbar.h,这两个库都可以通过 brew 安装。

brew install imagemagick
brew install zbar
1
2

因为从源码编译对我来说实在是太复杂了,所以我就选择了直接安装相关依赖。

# 编译

g++ -o scan_image scan_image.cpp
1

执行上面的命令,会报错:

scan_image.cpp:1:10: fatal error: 'Magick++.h' file not found
1

这是因为 Magick++.h 的头文件在 /opt/homebrew/include/ImageMagick-7/Magick++.h,但是 g++ 默认只会在 /opt/homebrew/include 目录下查找头文件,所以我们需要指定头文件的路径。

g++ -o scan_image scan_image.cpp -I/opt/homebrew/include/ImageMagick-7
1

执行上面的命令还是会有报错:

/opt/homebrew/include/ImageMagick-7/MagickCore/magick-config.h:63:3: warning: "you should set MAGICKCORE_QUANTUM_DEPTH to sensible default set it to configure time default" [-W#warnings]
# warning "you should set MAGICKCORE_QUANTUM_DEPTH to sensible default set it to configure time default"
  ^
/opt/homebrew/include/ImageMagick-7/MagickCore/magick-config.h:64:3: warning: "this is an obsolete behavior please fix your makefile" [-W#warnings]
# warning "this is an obsolete behavior please fix your makefile"
  ^
/opt/homebrew/include/ImageMagick-7/MagickCore/magick-config.h:86:3: error: "you should set MAGICKCORE_HDRI_ENABLE"
# error "you should set MAGICKCORE_HDRI_ENABLE"
  ^
/opt/homebrew/include/ImageMagick-7/MagickCore/magick-config.h:121:3: error: "you should set MAGICKCORE_HDRI_ENABLE"
# error "you should set MAGICKCORE_HDRI_ENABLE"
1
2
3
4
5
6
7
8
9
10
11

我们需要设置两个 ImageMagick 需要的编译变量:

g++ -o scan_image scan_image.cpp -I/opt/homebrew/include/ImageMagick-7 -DMAGICKCORE_QUANTUM_DEPTH=16 -DMAGICKCORE_HDRI_ENABLE=0
1

设置了这两个变量之后,还是会报错:

Undefined symbols for architecture arm64:
  "Magick::Blob::Blob()", referenced from:
      _main in scan_image-727bdc.o
  "_zbar_get_symbol_name", referenced from:
      zbar::Symbol::get_type_name() const in scan_image-727bdc.o
ld: symbol(s) not found for architecture arm64
clang: error: linker command failed with exit code 1 (use -v to see invocation)
1
2
3
4
5
6
7

这是因为我们只引用了头文件,却没有引用相关库的实现。我们需要指定 ImageMagick 的库文件路径,这里我使用的是 brew 安装的 ImageMagick,所以库文件在 /opt/homebrew/lib/ImageMagick 目录下。

g++ -o scan_image scan_image.cpp -I/opt/homebrew/include/ImageMagick-7 -L/opt/homebrew/lib/ImageMagick -DMAGICKCORE_QUANTUM_DEPTH=16 -DMAGICKCORE_HDRI_ENABLE=0 -lMagick++-7.Q16HDRI -lzbar
1

同时我们需要使用 -l 参数来指定需要链接的库,这里需要链接 Magick++-7.Q16HDRI 和 zbar。

# CMake

上面的编译命令比较长,而且如果我们需要编译多个文件的时候,就需要写很多次,所以我们可以使用 CMake 来简化编译过程。

cmake_minimum_required(VERSION 3.10)
project(ScanImage)


set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_FLAGS "-DMAGICKCORE_HDRI_ENABLE=1 -DMAGICKCORE_QUANTUM_DEPTH=16")

include_directories(/opt/homebrew/include/ImageMagick-7)
link_directories(/opt/homebrew/lib/ImageMagick)

add_executable(ScanImage scan_image.cpp)
target_link_libraries(ScanImage zbar Magick++-7.Q16HDRI)
1
2
3
4
5
6
7
8
9
10
11
12

# 总结

C++ 的编译报错总是让人摸不着头脑,这里我只是简单的记录了下我遇到的问题和解决方案,希望能帮助到大家。

# 参考

how to #include third party libraries (opens new window)

zbar-wasm (opens new window)

正则表达式匹配信用卡

最近在做支付相关的服务,需要检测用户输入的信用卡号是否合法,并且根据信用卡号规则显示对应的信用卡类型。这里记录一下如何使用正则表达式来匹配信用卡号。顺便说一下只有 AE 卡号的 CVV 是 4 位的,其他的都是 3 位。

# 银联卡

银联卡以 62 开头,借记卡是 19 位,信用卡是 14 位。一般支付的时候都是使用信用卡,所以我们只需要匹配 14 位的卡号。

const regex = new RegExp('^62\\d{14}');
1

# Visa

Visa 信用卡以 4 开头,新卡长度为 16 位,旧卡长度为 13 位。

const regex = new RegExp('^4[0-9]{12}(?:[0-9]{3})?');
1

# MasterCard

MasterCard 信用卡以 51 到 55 开头或者是以 2221–2720 开头,长度为 16 位。

const regex = new RegExp('^(5[1-5]\\d{0,2}|22[2-9]\\d{1}|2[3-7]\\d{2})\\d{12}');
1

# Amex

Amex 信用卡以 34 或者 37 开头,长度为 15 位。

const regex = new RegExp('^3[47]\\d{13}');
1

# Jcb

Jcb 信用卡以 35 开头,长度为 16 位。以 2131 或者 1800 开头,长度为 15 位。

const regex = new RegExp('^(?:2131|1800|35\\d{3})\\d{11}');
1

# Diners

Diners 信用卡以 36、38 或者 30[0-5] 开头,长度为 14 位。

const regex = new RegExp('^3(?:0([0-5]|9)|[68]\\d)\\d{11}');
1

# 总结

信用卡号的判断并不复杂,但是很多卡号有些特殊情况,需要注意。

# 参考

Payment card number (opens new window)

Finding or Verifying Credit Card Numbers (opens new window)