Homebrew 是一款自由及开放源代码的软件包管理系统,用以简化macOS系统上的软件安装过程。
其核心是一个托管在 GitHub上 的 git 版本库,由于某些原因,国内访问速度不快,并且稳定性堪忧。

为了提高体验,我们可以用腾讯软件源对其进行加速,打开“终端”,依次执行以下命令即可:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
# 替换 Homebrew 的 formula 索引的镜像(即 brew update 时所更新内容)
git -C "$(brew --repo)" remote set-url origin https://mirrors.cloud.tencent.com/homebrew/brew.git
git -C "$(brew --repo homebrew/core)" remote set-url origin https://mirrors.cloud.tencent.com/homebrew/homebrew-core.git

# 替换 Homebrew 二进制预编译包的镜像
echo 'export HOMEBREW_BOTTLE_DOMAIN=https://mirrors.cloud.tencent.com/homebrew-bottles' >> ~/.bash_profile
source ~/.bash_profile

#(可选)禁用“自动更新” —— 执行`brew install xxx`时会自动执行`brew update`,导致安装过程比较慢。
# 通过此方法禁用后,选择合适时机手动执行`brew update`
echo 'export HOMEBREW_NO_AUTO_UPDATE=1' >> ~/.bash_profile
source ~/.bash_profile

# 更新
brew update
```

复原:
```bash
git -C "$(brew --repo)" remote set-url origin https://github.com/Homebrew/brew.git

git -C "$(brew --repo homebrew/core)" remote set-url origin https://github.com/Homebrew/homebrew-core

brew update

# Homebrew-bottles: 需要去`~/.bash_profile`中删除'HOMEBREW_BOTTLE_DOMAIN'

本博客目前是使用 hexo + Next 主题搭建在 GitHub Pages 上的,使用 git 管理,并接入了 Travis-CI 自动发布。一直以来,对于图片的处理是我的一块心病。虽然hexo官方提出了资源文件夹的概念,但是这种方式几乎不被任何 Markdown 编辑器支持。

个人习惯是使用 Typora 码字,然后再用 vscode 的 markdownlint 扩展进行语法检查(代码格式上的洁癖)—— vscode 用得顺手,甚至可以放弃 Typora。

为了不滥用GitHub仓库、节省空间和提高访问速度,可以使用腾讯云的对象存储(COS) + 内容分发网络(CDN)。良心云每个月都赠送了一定的免费额度,对于个人博客来讲一般是够用的。

最近CDN也不能满足我的胃口了,在尝试极限优化的路上,我又发现了一个更有想象力的方案,那就是借助腾讯云的数据万象(原万象优图)服务,对图片进行预处理或者实时处理,从而减小图片体积、提高打开速度。

对于数据万象我在之前的一篇文章薅羊毛党的胜利 —— 合理利用腾讯云搭建服务 提到过。

阅读全文 »

市面上有什么好用的从服务器推报警和日志到手机的工具?之前私下用的是[Server酱]的服务,非常方便。
但是考虑到安全原因,这个服务如果用在生产环境心里还是有点慌(虽然我相信[Server酱]是很有节操的)。

另外,出于想把工作和生活分开的私心(并不能),所以一直在探索使用企业微信来实现通知的方案(自建应用的话还要考虑通知的到达率,实在有心无力)。

之前已经基于企业微信的自建应用API,开发和部署了一个服务,技术方案是 docker + django + mysql + celery + redis。开发时要达到高可用,涉及 access_token 的刷新,还要考虑任务队列、分布式锁等等,真是折腾。

今天(2019-6-28)在更新企业微信时,发现增加了个群机器人的功能,赶紧查了一下文档发现挺符合需求的。群机器人的优点是,通知基于群组,有问题时直接可以在群内沟通,也不会存在重新拉群还需要介绍背景,人员发生变动时拉新人进群即可。

监控报警的脚本可以放在自己的服务器上,但是一旦遇到光纤被挖断了、停电这种外部因素,就需要一些外部手段来监控了。这里我推荐一下腾讯云无服务器云函数(Serverless Cloud Function,SCF),免费,如果用腾讯云的其它服务还有各种加成,现在还有【活动链接】(写个简单的demo就行)送腾讯云的通用代金券、公仔等。

这里我就写个简单的天气小助手,来演示一下整个流程。

阅读全文 »

浅析 ADB 原理和优化

最近研究小程序自动化的时候,拜读了几篇关于小程序原理的文章,其中提到了一个词”管控”。作为平台方,必须保证提供的服务是可控的(细节与主题无关,这里不再展开)。受此启发,对于我们的平台来说,如果希望对外提供自动化能力,就必须对执行环境做一定的保护。如果具体到 android 平台,那首先要研究的就是 ADB(Android Debug Bridge)。

具体要管控什么?举个例子,执行adb kill-server 会使 adb server 退出——因为是 adb server 提供的接口,所以不涉及权限问题(即使 adb server 是通过 root 权限启动,普通用户通过 adb client 调用此接口,adb server 也会退出。)。

阅读全文 »

Uiautomator2 源码分析

引言

关于著名的软件测试金字塔理论,可以看一下 The Practical Test Pyramid 这篇文章,译文在这里

对于UI自动化测试,根据其实现原理可以大致分为:基于坐标的(monkeyrunner)、基于控件的(uiautomator)、基于图像识别的(sikuli)等。针对不同的测试场景,不同方案各有其用武之地。

Android Uiautomator2 Python Wrapper 是基于 Google uiautomator2 库实现的自动化测试框架。该框架主要解决了两大痛点:

  1. 测试脚本只能使用Java语言
  2. 测试脚本必须每次被上传到设备上运行

其实现原理就是在手机上运行了一个 http 服务器,将 uiautomator 中的功能开放出来,然后再将这些 http 接口,封装成 Python 库。

阅读全文 »

几种常见的身份认证方案和接口测试中的应用

最近做了几个项目的接口测试接入工作,主要是结合星海(内部的统一接口测试平台)完成各个项目基础框架的搭建,并结合项目实际情况混合普通(通过网页编辑)和高级模式(直接编写代码),来提升接口测试的整体效率。

身份认证

几乎所有项目遇到的首个问题就是身份认证。因为大部分接口都不允许、也不应该匿名使用,所以一般都会通过HTTP Header或URL中的Query String携带一个令牌(token),来表明用户身份。

一般来讲,token 如果根据有效期来分类的话,有永久有效(当然可以后台手动吊销)和一定时间内有效两类。根据权限又可以分为完全权限和指定作用阈。根据项目实际情况,可能还有更多的划分。

一个典型的认证流程:

  1. 用户向服务器发送用户名和密码。
  2. 服务器验证通过后,在当前对话(session)里面保存相关数据,比如用户角色、登录时间等等。
  3. 服务器向用户返回一个 session_id,写入用户的 Cookie。
  4. 用户随后的每一次请求,都会通过 Cookie,将 session_id 传回服务器。
  5. 服务器收到 session_id,找到前期保存的数据,由此得知用户的身份。

这种模式的问题在于,扩展性(scaling)不好。单机当然没有问题,如果是服务器集群,或者是跨域的服务导向架构,就要求 session 数据共享,每台服务器都能够读取 session。

所以,后来又有了 JWT(JSON Web Token)方案。详细的原理和用法这里就不展开了,可以读一下阮一峰的《JSON Web Token 入门教程》,或 Auth0 出品的《JWT Handbook》。

另外,前面提到的典型认证流程,第一步是通过用户名和密码认证。但是对于第三方服务(例如饿了么之于微信),还会用到 OAuth2.0的标准。简单描述就是,用户点击“同意”授权,由微信和饿了么在后台完成鉴权,最后颁发一个短期有效的令牌。具体的原理也可以通过阮一峰的《理解OAuth 2.0》了解。

身份认证与接口测试

阅读全文 »

最近写自动化脚本的时候,遇到一个问题:(为了便于理解,这里拿QQ音乐举例,实际是一个内部项目不方便透露),打开QQ音乐,选择一首歌曲-播放,在播放器界面按home键回到桌面,再点击桌面快捷方式返回QQ音乐,现象:手动操作返回的是播放器界面(即回到桌面之前的界面),但是通过代码执行,返回的却是QQ音乐的首页。本文就造成这一问题的原因和分析过程做个记录,便于以后回顾。
阅读全文 »

这里以chrome为例。

其中apk文件为chrome-67-0-3396-87.apk,对应的包名为com.android.chrome

有apk

方式一:minSdkVersion-可以、targetSdkVersion-可以

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
$ aapt list -a chrome-67-0-3396-87.apk |grep -i sdk
A: android:compileSdkVersion(0x01010572)=(type 0x10)0x1c
A: android:compileSdkVersionCodename(0x01010573)="9" (Raw: "9")
E: uses-sdk (line=3)
A: android:minSdkVersion(0x0101020c)=(type 0x10)0x10
A: android:targetSdkVersion(0x01010270)=(type 0x10)0x1c
E: uses-permission-sdk-23 (line=10)
E: uses-permission-sdk-23 (line=15)
E: uses-permission-sdk-23 (line=16)
E: uses-permission-sdk-23 (line=17)
E: uses-permission-sdk-23 (line=18)
A: android:name(0x01010003)="com.samsung.android.sdk.multiwindow.enable" (Raw: "com.samsung.android.sdk.multiwindow.enable")
A: android:name(0x01010003)="com.samsung.android.sdk.multiwindow.multiinstance.enable" (Raw: "com.samsung.android.sdk.multiwindow.multiinstance.enable")
A: android:name(0x01010003)="com.samsung.android.sdk.multiwindow.multiinstance.launchmode" (Raw: "com.samsung.android.sdk.multiwindow.multiinstance.launchmode")
A: android:name(0x01010003)="com.samsung.android.sdk.multiwindow.penwindow.enable" (Raw: "com.samsung.android.sdk.multiwindow.penwindow.enable")

注意,这里取出来的值是16进制的,需要转换为10进制使用。
python 16进制转10进制: int('0x10', 16) = 16

方式二:minSdkVersion-可以、targetSdkVersion-可以

1
2
3
4
5
6
7
8
9
10
11
12
13
$ aapt d badging chrome-67-0-3396-87.apk |grep -i sdk
package: name='com.android.chrome' versionCode='339608700' versionName='67.0.3396.87' compileSdkVersion='28' compileSdkVersionCodename='9'
sdkVersion:'16'
targetSdkVersion:'28'
uses-permission-sdk-23: name='android.permission.ACCESS_WIFI_STATE'
uses-permission-sdk-23: name='android.permission.BLUETOOTH'
uses-permission-sdk-23: name='android.permission.BLUETOOTH_ADMIN'
uses-permission-sdk-23: name='android.permission.REORDER_TASKS'
uses-permission-sdk-23: name='android.permission.REQUEST_INSTALL_PACKAGES'
uses-feature-sdk-23: name='android.hardware.bluetooth'
uses-implied-feature-sdk-23: name='android.hardware.bluetooth' reason='requested android.permission.BLUETOOTH permission, requested android.permission.BLUETOOTH_ADMIN permission, and targetSdkVersion > 4'
uses-feature-sdk-23: name='android.hardware.wifi'
uses-implied-feature-sdk-23: name='android.hardware.wifi' reason='requested android.permission.ACCESS_WIFI_STATE permission'

minSdkVersion对应的应该是这里的sdkVersion

没有apk(已安装在手机中):minSdkVersion-不行、targetSdkVersion-可以

1
2
$ adb shell dumpsys package com.android.chrome|grep -i sdk
versionCode=339608700 targetSdk=28

注意:sdk可能是小写、可能是大小写混合,所以grep命令要使用-i参数,指定忽略大小写

0%