苹果开发者账号添加团队成员

背景

近期在处理苹果开发账号相关的事情,包括添加团队成员、创建使用证书、编译打包、真机测试安装、提交审核上架等。

目前是公司内部团队进行开发,账号类型为公司账号,添加一个团队成员协同开发。

苹果开发者账号下的团队成员有三种角色:

  • Team Agent (代理) 就是申请注册开发者账号的那一个,权限最高,续费和创建开发商证书只能使用该账号。
  • Admin (管理) 管理分发证书、管理测试设备、管理应用配置等等。
  • Member (成员) 没有管理权限,只能下载和请求数据,只能做开发过程中真机调试。

官方帮助:https://developer.apple.com/cn/help/account/manage-your-team/invite-team-members/

步骤

  1. appstore connect

    image-20231229161007400

  2. 邀请

    注意要选择可以访问 访问证书、标识符和描述文件,不过 云端管理的分发证书这个看情况。

    image-20231229161053322


mac 下使用 homebrew 安装 chrome

真是一波三折血泪史。

起因是要装 chromedriver,先看了官方的地址:https://chromedriver.chromium.org/downloads

怎么回事,不能装最新的,只能装114版本?

image-20231228203906566

看样子 homebrew 的版本没有114的,还是用老一点的chrome版本,才能和官方稳定的 chromedriver 搭配干活。

brew info --cask google-chrome
brew install --cask google-chrome@114

image-20231228175313073

完了,homebrew没有这个版本。网上乱七八糟的不放心,还是找比较像官方的:

image-20231228175117088

下载下来发现用不了,无法运行。

image-20231228204036638

算了,直接源码编译:https://chromium.googlesource.com/chromium/src/+refs

我用了114版本:https://chromium.googlesource.com/chromium/src/+/refs/tags/114.0.5735.346

放弃,怎么可能自己编译?!

telegram-cloud-photo-size-5-6084706307870407256-y

又认真看了下,120和对应的chromedriver,这不是有吗?https://googlechromelabs.github.io/chrome-for-testing/

image-20231228204117384

image-20231228204355700

下载好了还是无法运行,心累了。

image-20231228205028976

死马当活马医吧,用 homebrew 把 chrome 和 chromedriver 都装完:

image-20231228205353704

试着跑一下 selenium-server 看:

image-20231228205951471

没问题。用代码跑看也是OK的。写了个简单的动态加载另一个python文件的方法,适合debug。

from selenium import webdriver
from selenium.webdriver.common.by import By
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC
from selenium.webdriver.common.action_chains import ActionChains
import time
import os
import subprocess
import random
import importlib

USERNAME=""
PASSWORD=""
WEBSITE="http://abc.com"
driver = webdriver.Chrome()
module_name = "oaread"
oaread_module = importlib.import_module(module_name)

def main():
    global WEBSITE
    global driver

    driver.get(WEBSITE)

    print('Enter ' + driver.title)
    # time.sleep(random.randint(4,9))
    username_xpath = '//input[contains(@id,"userName")]'
    password_xpath = '//input[contains(@id,"password")]'
    login_button_xpath = '//*[@id="main"]/table/tbody/tr/td/div[2]/div/login-tab/div/div[2]/div[2]/div[1]'

    try:
        username_elem = WebDriverWait(driver, 10).until(
            EC.presence_of_element_located((By.XPATH, username_xpath))
        )
                # 输入用户名
        username_elem.send_keys(USERNAME)
        # print(username_elem.get_attribute('outerHTML'))

        # 等待密码输入框可见
        password_elem = WebDriverWait(driver, 10).until(
            EC.visibility_of_element_located((By.XPATH, password_xpath))
        )

        # 输入密码
        password_elem.send_keys(PASSWORD)
        # print(password_elem.get_attribute('outerHTML'))

        # 添加等待时间,模拟人为操作的速度
        time.sleep(1)
        # 等待登录按钮可见
        login_button_elem = WebDriverWait(driver, 10).until(
            EC.visibility_of_element_located((By.XPATH, login_button_xpath))
        )

        # 点击登录按钮
        login_button_elem.click()
        step_enter_oaread(driver)

    except Exception as e:
        print(e)

    # step_oa_read(driver)
    monitor_and_execute(module_name+".py", driver)

def get_file_modification_time(file_path):
    """
    获取文件的修改时间
    """
    return os.path.getmtime(file_path)

def monitor_and_execute(script_path, driver):
    """
    监控文件是否有更新,如果有更新则执行脚本
    """
    last_modification_time = get_file_modification_time(script_path)

    while True:
        current_modification_time = get_file_modification_time(script_path)

        if current_modification_time > last_modification_time:
            print("File has been updated. Executing the script.")
            last_modification_time = current_modification_time
            importlib.reload(oaread_module)
            try:
                oaread_module.my_run(driver)
            except Exception as e:
                print("执行出错,不管了")
                print(e)
            print("sleep 1")
            time.sleep(1)

def step_oa_read(driver):
    errCount = 10
    while errCount > 0:
        try:
            oaread_module.step_first_item(driver)
            time.sleep(random.randint(2,4))
            oaread_module.step_item_replay(driver)
        except Exception as e:
            errCount -= 1
            print(e)
            print("执行出错,不管了")
            time.sleep(random.randint(10,20))
        time.sleep(random.randint(1,2))
        oaread_module.my_first_window(driver)

def step_enter_oaread(driver):
    driver.get('http://abc.com)

if __name__=="__main__":
    errCount = 10
    while errCount > 0:
        errCount -= 1
        main()

image-20231229160614810


mac 快速使用 nginx

安装

brew install nginx

image-20231226085242585

配置文件

/opt/homebrew/etc/nginx/nginx.conf

配置设置和常用的nginx是一样的。默认的目录和文件:

brew info nginx

image-20231226100551078

虽然 homebrew 已经安装nginx成功了。但是 nginx并未被正确安装到Homebrew的默认目录,brew services 可能无法找到正确的安装路径而报错。

image-20231226100814580

常用命令

image-20231226102045020

brew services reload nginx
brew services start nginx
brew services stop nginx

image-20231226102556460

image-20231226102150606

针对 Jekyll 和 markdown 的配置优化

对于本地的一些临时目录里的图片,如果按照正常的nginx请求,是进不来的。这里就要对404的请求做二次改正,这里是我最终的配置:

image-20240110下午44206031

主要思路是

  • 将匹配类似 /category/2024/01/10/ 的路径段,并将其从 URI 中去掉。
  • 然后,root $new_root; 将新的 root 路径设置为 /Users/kelu/Workspace/blog/_posts
  • 接着使用 try_files $uri =404; 尝试访问文件。

这样,对于 Typora 等 markdown 工具,自动将图片以相对目录的方式保存下来,也可以展示在 网站上。

    root /Users/kelu/Workspace/blog/_site;
    index index.html;

    location / {
        try_files $uri $uri/ @fallback;
    }

    location @fallback {
        # 设置新的root路径
        set $new_root /Users/kelu/Workspace/blog/_posts;

        # 使用正则表达式捕获组提取除了特定字符串之外的路径
        rewrite ^/([^/]+/[^/]+/[^/]+/[^/]+)/(.*)$ /$2 break;

        # 尝试访问新的root路径
        root $new_root;
        try_files $uri =404;
    }

参考资料


mac 命令行使用 vscode 打开当前目录

  1. 安装命令行工具: 打开 VSCode,然后按 Cmd + Shift + P 打开命令面板,输入 “shell command” 并选择 “Shell Command: Install ‘code’ command in PATH”。这将会在命令行中添加 code 命令。

    image-20231214171531639

    image-20231214171543081

  2. 使用 code 命令打开目录: 在目标目录中,运行以下命令:

    bashCopy code
    code .
    

    image-20231214171614210


macOS 下的 systemd —— launchd

背景

在 macOS 中,Launchd 是一个系统级别的进程管理工具,用于启动、停止和管理系统和用户级别的进程。Launchd 进程本身是由内核启动的,并负责启动其他进程,包括系统服务和用户级别的进程。

Launchd 启动的进程通常会将输出日志写入系统日志,我们可以使用 macOS 提供的 Console 应用程序来查看这些日志。

编写 launchd 配置文件

launchd 的配置文件是通过一个 plist 文件来定义的(plistproperty list 的缩写),一个典型的格式如下:

<?xml version="1.0" encoding="UTF-8"?>  
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">  
<plist version="1.0">  
<dict>  
  <!-- Label 可以看作是守护进程的名称,key 是配置的名称,key 的下一行就是它的值,string 标签表示值的类型是字符串 -->  
  <key>Label</key>  
  <string>com.example.app</string>  
  <key>Program</key>  
  <string>/Users/Me/Scripts/cleanup.sh</string>  
  <key>RunAtLoad</key>  
  <true/>  
</dict>  
</plist>  

说明:

  • 配置文件中,除了 dict 里面的那一部分,其他的都是固定的,不需要修改。
  • 三个字段说明:
  • Label:也就是服务的名字,可以随便取,但是不能重复。我们通过 launchctl list 来查看的时候,列出的就是这个名字。上述例子是 com.example.app
  • Program:要启动的程序的路径,需要填写绝对路径。上述例子是 /Users/Me/Scripts/cleanup.sh如果需要加参数的话,需要使用 ProgramArguments 来代替 Program
  • RunAtLoad:是否在配置被加载的时候就运行,默认是 false,如果需要在启动的时候就运行,需要设置为 true。上述例子是 true
  • 标签说明:key 就是属性的名称,紧跟着 key 的下一行就是属性的值,属性的值的类型通过其标签反映出来,比如上面的 <string> 表示包裹的是一个字符串类型,而 <true/> 表示是一个布尔类型,而且它的值是 true

mac 中很多配置都是通过 plist 来定义的,

macOS 中有两种类型的守护进程,一种是系统级别的(Daemons),一种是用户级别的(Agents),它们的配置文件放的位置是不一样的。

下面是 launchd 配置文件的路径:

  • ~/Library/LaunchAgents:用户级别的守护进程配置文件路径。这里保存特定用户的 Agents 配置。(一般情况都是放这里
  • /Library/LaunchAgents:用户级别的守护进程配置文件路径。这里保存所有用户共用的 Agents 配置。
  • /Library/LaunchDaemons:全局的 Daemons 配置。
  • /System/Library/LaunchAgents:所有登录用户共用的 Agents 配置。
  • /System/Library/LaunchDaemons:全局的 Daemons 配置。

常用命令

列出所有 launchd 管理的服务

launchctl list
  • 第一列是进程 id,如果是 0 说明没有在运行状态。
  • 第二列的 0 表示的是进程上一次的退出状态码,0 一般表示成功。
  • 第三列表示的是我们在 plist 配置文件中配置的 Label 的值。

开机启动/不启动

launchctl load ~/Library/LaunchAgents/com.example.app.plist  
launchctl unload ~/Library/LaunchAgents/com.example.app.plist  

相当于systemctl enable xxxsystemctl disable xxx

启动/停止

launchctl start com.example.app 
launchctl stop com.example.app

相当于 systemctl start xxxsystemctl stop xxx

案例frps

文件 ~/Library/LaunchAgents/frpc.plist

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
  <key>KeepAlive</key>
  <true/>
  <key>Label</key>
  <string>frpc</string>
  <key>ProgramArguments</key>
  <array>
    <string>/Users/kelu/Workspace/bin/frp_0.52.3_darwin_arm64/frpc</string>
    <string>-c</string>
    <string>/Users/kelu/Workspace/bin/frp_0.52.3_darwin_arm64/tmp.toml</string>
  </array>
  <key>RunAtLoad</key>
  <true/>
</dict>
</plist>

KeepAlive,指定后台保持运行

这个配置文件的作用是,以守护进程的方式来启动命令。

launchctl load ~/Library/LaunchAgents/frpc.plist  

image-20231211094334367

确认已经运行

ps aux | grep frpc

查看日志,目前我用 console 查不出来 frpc 的日志,先放着了。

某些网络会对长时间的udp连接做重置,所以我们本地耶可以设置定时任务杀掉frpc。

参考资料