Cpiz's blog

  • 首页

  • 关于

  • 标签

  • 分类

  • 归档

  • 搜索

编译Windows 64bit平台pysqlcipher3 for Python3.7

发表于 2019-01-23 | 分类于 技术

编译与安装

  1. 安装Python3 64bit

    https://www.python.org/ftp/python/3.7.2/python-3.7.2-amd64.exe

  2. 安装OpenSSL

    https://slproweb.com/products/Win32OpenSSL.html

    这里使用了Win64 OpenSSL v1.0.2q版本。

    注意需要将OpenSSL的dll安装到系统目录,如果只是安装在OpenSSL的bin目录的话,使用的时候需要将bin目录加入系统PATH,或者自行拷贝相关dll到调用程序目录。
    image.png-21.2kB

  3. 安装Tcl Windows(64-bit, x64)

    https://www.activestate.com/products/activetcl/downloads/

    我使用了8.6.8.0版本。

  4. 安装 VisualStudio 2017

    https://visualstudio.microsoft.com/zh-hans/downloads/

    社区版即可,只须安装“使用C++的桌面开发”相关工具集。

    image.png-130kB

  5. 下载 sqlcipher

    1
    D:\MyDocs\Desktop>git clone https://github.com/sqlcipher/sqlcipher.git
  6. 生成sqlite3源码

    从开始菜单找到适用于 VS 2017 的 x64 本机工具命令提示,启动,打开附带了VS工作环境的控制台。

    image.png-9.9kB

    切换到sqlcipher源码目录,执行

    1
    D:\MyDocs\Desktop\sqlcipher>nmake /f Makefile.msc

    结果

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    Microsoft (R) 程序维护实用工具 14.16.27026.1 版
    版权所有 (C) Microsoft Corporation。 保留所有权利。

    copy .\tool\lempar.c .
    已复制 1 个文件。
    cl -nologo -W4 -MT -DNDEBUG -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -O2 -Zi -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706 -Daccess=_access -Felemon.exe .\tool\lemon.c /link /DEBUG
    lemon.c
    del /Q parse.y parse.h parse.h.temp 2>NUL
    copy .\src\parse.y .
    已复制 1 个文件。
    .\lemon.exe -DSQLITE_MAX_TRIGGER_DEPTH=100 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_STMTVTAB=1 -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 -DSQLITE_INTROSPECTION_PRAGMAS=1 -DSQLITE_ENABLE_DESERIALIZE=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 parse.y
    move parse.h parse.h.temp
    移动了 1 个文件。
    tclsh .\tool\addopcodes.tcl parse.h.temp > parse.h
    type parse.h .\src\vdbe.c | tclsh .\tool\mkopcodeh.tcl > opcodes.h

    parse.h



    .\src\vdbe.c


    tclsh .\tool\mkopcodec.tcl opcodes.h > opcodes.c
    cl -nologo -W4 -MT -DNDEBUG -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -O2 -Zi -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706 -Femkkeywordhash.exe -DSQLITE_MAX_TRIGGER_DEPTH=100 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_STMTVTAB=1 -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 -DSQLITE_INTROSPECTION_PRAGMAS=1 -DSQLITE_ENABLE_DESERIALIZE=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 .\tool\mkkeywordhash.c /link /DEBUG
    mkkeywordhash.c
    .\mkkeywordhash.exe > keywordhash.h
    tclsh .\tool\mkshellc.tcl > shell.c
    cl -nologo -W4 -MT -DNDEBUG -D_CRT_SECURE_NO_DEPRECATE -D_CRT_SECURE_NO_WARNINGS -D_CRT_NONSTDC_NO_DEPRECATE -D_CRT_NONSTDC_NO_WARNINGS -O2 -Zi -wd4054 -wd4055 -wd4100 -wd4127 -wd4130 -wd4152 -wd4189 -wd4206 -wd4210 -wd4232 -wd4305 -wd4306 -wd4702 -wd4706 -Femksourceid.exe .\tool\mksourceid.c /link /DEBUG
    mksourceid.c
    tclsh .\tool\mksqlite3h.tcl . > sqlite3.h
    copy .\ext\fts5\fts5parse.y .
    已复制 1 个文件。
    del /Q fts5parse.h 2>NUL
    .\lemon.exe -DSQLITE_MAX_TRIGGER_DEPTH=100 -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_GEOPOLY=1 -DSQLITE_ENABLE_JSON1=1 -DSQLITE_ENABLE_STMTVTAB=1 -DSQLITE_ENABLE_DBPAGE_VTAB=1 -DSQLITE_ENABLE_DBSTAT_VTAB=1 -DSQLITE_INTROSPECTION_PRAGMAS=1 -DSQLITE_ENABLE_DESERIALIZE=1 -DSQLITE_ENABLE_COLUMN_METADATA=1 fts5parse.y
    tclsh .\ext\fts5\tool\mkfts5c.tcl
    copy .\ext\fts5\fts5.h .
    已复制 1 个文件。
    rmdir /Q/S tsrc 2>NUL
    mkdir tsrc
    for %i in (.\src\crypto.c .\src\crypto_cc.c .\src\crypto_impl.c .\src\crypto_libtomcrypt.c .\src\crypto_openssl.c .\src\crypto.h .\src\sqlcipher.h .\src\alter.c .\src\analyze.c .\src\attach.c .\src\auth.c .\src\backup.c .\src\bitvec.c .\src\btmutex.c .\src\btree.c .\src\build.c .\src\callback.c .\src\complete.c .\src\ctime.c .\src\date.c .\src\dbpage.c .\src\dbstat.c .\src\delete.c .\src\expr.c .\src\fault.c .\src\fkey.c .\src\func.c .\src\global.c .\src\hash.c .\src\insert.c .\src\legacy.c .\src\loadext.c .\src\main.c .\src\malloc.c .\src\mem0.c .\src\mem1.c .\src\mem2.c .\src\mem3.c .\src\mem5.c .\src\memdb.c .\src\memjournal.c .\src\mutex.c .\src\mutex_noop.c .\src\mutex_unix.c .\src\mutex_w32.c .\src\notify.c .\src\os.c .\src\os_unix.c .\src\os_win.c) do copy /Y %i tsrc

    ......略

    NMAKE : fatal error U1077: “"C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX64\x64\cl.EXE"”: 返回代码“0x2”
    Stop.

    最终编译会报错,不过没关系,我们这里并不需要真正的编译,只需要中间生成的sqlite3.h和sqlite3.c就够了。

    中间过程如果执行有其他差错,可以clean一下再重试:

    1
    D:\MyDocs\Desktop\sqlcipher>nmake /f Makefile.msc clean
  7. 编译正式的sqlcipher控制台程序(非必须)

    这并不是 pysqlcipher3 需要的,但如果自己想成功编译一份 sqlcipher 的 Windows 程序,可以参考这篇 Win64 setup — Compiling SQLCipher,修改Makefile.msc再构建。

  8. 下载 pysqlcipher3

    1
    git clone https://github.com/rigglemania/pysqlcipher3.git
  9. 在pysqlcipher3目录下创建amalgamation目录,拷贝上一步 sqlcipher 项目目录中生成的sqlite3.h和sqlite3.c文件到其中。并在其下创建一个sqlcipher目录,且再次拷贝一份sqlite3.h文件到sqlcipher目录中。

  10. 执行编译

    1
    D:\MyDocs\Desktop\pysqlcipher3>python setup.py build_amalgamation

    结果

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    D:\MyDocs\Desktop\pysqlcipher3>python setup.py build_amalgamation
    running build_amalgamation
    Builds a C extension using a sqlcipher amalgamation
    building 'pysqlcipher3._sqlite3' extension
    creating build\temp.win-amd64-3.7
    creating build\temp.win-amd64-3.7\Release
    creating build\temp.win-amd64-3.7\Release\src
    creating build\temp.win-amd64-3.7\Release\src\python3
    creating build\temp.win-amd64-3.7\Release\amalgamation
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\module.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\module.obj
    module.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\connection.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\connection.obj
    connection.c
    src\python3\connection.c(1546): warning C4090: “=”: 不同的“const”限定符
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\cursor.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\cursor.obj
    cursor.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\cache.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\cache.obj
    cache.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\microprotocols.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\microprotocols.obj
    microprotocols.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\prepare_protocol.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\prepare_protocol.obj
    prepare_protocol.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\statement.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\statement.obj
    statement.c
    src\python3\statement.c(138): warning C4090: “=”: 不同的“const”限定符
    src\python3\statement.c(158): warning C4244: “函数”: 从“Py_ssize_t”转换到“int”,可能丢失数据
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\util.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\util.obj
    util.c
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcsrc\python3\row.c /Fobuild\temp.win-amd64-3.7\Release\src\python3\row.obj
    row.c
    src\python3\row.c(101): warning C4090: “=”: 不同的“const”限定符
    src\python3\row.c(111): warning C4090: “=”: 不同的“const”限定符
    src\python3\row.c(168): warning C4244: “=”: 从“Py_ssize_t”转换到“int”,可能丢失数据
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\cl.exe /c /nologo /Ox /W3 /GL /DNDEBUG /MD -DMODULE_NAME=\"pysqlcipher3.dbapi2\" -DSQLITE_ENABLE_FTS3=1 -DSQLITE_ENABLE_RTREE=1 -DSQLITE_ENABLE_LOAD_EXTENSION=1 -DSQLITE_HAS_CODEC=1 -DSQLITE_TEMP_STORE=2 -Dinline=__inline -Iamalgamation -Id:\Work\OpenSSL-Win64\include -ID:\work\Python37\include -ID:\work\Python37\include "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\include" "-IC:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\include" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\shared" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\um" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\winrt" "-IC:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\cppwinrt" /Tcamalgamation\sqlite3.c /Fobuild\temp.win-amd64-3.7\Release\amalgamation\sqlite3.obj
    sqlite3.c
    amalgamation\sqlite3.c(23097): warning C4996: 'fopen': This function or variable may be unsafe. Consider using fopen_s instead. To disable deprecation, use _CRT_SECURE_NO_WARNINGS. See online help for details.
    C:\Program Files (x86)\Windows Kits\10\include\10.0.17763.0\ucrt\stdio.h(208): note: 参见“fopen”的声明
    C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\bin\HostX86\x64\link.exe /nologo /INCREMENTAL:NO /LTCG /DLL /MANIFEST:EMBED,ID=2 /MANIFESTUAC:NO /LIBPATH:D:\work\Python37\libs /LIBPATH:D:\work\Python37\PCbuild\amd64 "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\ATLMFC\lib\x64" "/LIBPATH:C:\Program Files (x86)\Microsoft Visual Studio\2017\Community\VC\Tools\MSVC\14.16.27023\lib\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\ucrt\x64" "/LIBPATH:C:\Program Files (x86)\Windows Kits\10\lib\10.0.17763.0\um\x64" /EXPORT:PyInit__sqlite3 build\temp.win-amd64-3.7\Release\src\python3\module.obj build\temp.win-amd64-3.7\Release\src\python3\connection.obj build\temp.win-amd64-3.7\Release\src\python3\cursor.obj build\temp.win-amd64-3.7\Release\src\python3\cache.obj build\temp.win-amd64-3.7\Release\src\python3\microprotocols.obj build\temp.win-amd64-3.7\Release\src\python3\prepare_protocol.obj build\temp.win-amd64-3.7\Release\src\python3\statement.obj build\temp.win-amd64-3.7\Release\src\python3\util.obj build\temp.win-amd64-3.7\Release\src\python3\row.obj build\temp.win-amd64-3.7\Release\amalgamation\sqlite3.obj /OUT:build\lib.win-amd64-3.7\pysqlcipher3\_sqlite3.cp37-win_amd64.pyd /IMPLIB:build\temp.win-amd64-3.7\Release\src\python3\_sqlite3.cp37-win_amd64.lib libeay32.lib /LIBPATH:d:\Work\OpenSSL-Win64\lib
    正在创建库 build\temp.win-amd64-3.7\Release\src\python3\_sqlite3.cp37-win_amd64.lib 和对象 build\temp.win-amd64-3.7\Release\src\python3\_sqlite3.cp37-win_amd64.exp
    正在生成代码
    已完成代码的生成
  11. 安装至python环境

    1
    D:\MyDocs\Desktop\pysqlcipher3>python setup.py install

    结果

    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
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    running install
    running bdist_egg
    running egg_info
    writing pysqlcipher3.egg-info\PKG-INFO
    writing dependency_links to pysqlcipher3.egg-info\dependency_links.txt
    writing top-level names to pysqlcipher3.egg-info\top_level.txt
    reading manifest file 'pysqlcipher3.egg-info\SOURCES.txt'
    reading manifest template 'MANIFEST.in'
    warning: no previously-included files matching '*~' found anywhere in distribution
    warning: no previously-included files matching '*.pyc' found anywhere in distribution
    writing manifest file 'pysqlcipher3.egg-info\SOURCES.txt'
    installing library code to build\bdist.win-amd64\egg
    running install_lib
    running build_py
    running build_ext
    Builds a C extension linking against libsqlcipher library
    creating build\bdist.win-amd64
    creating build\bdist.win-amd64\egg
    creating build\bdist.win-amd64\egg\pysqlcipher3
    copying build\lib.win-amd64-3.7\pysqlcipher3\dbapi2.py -> build\bdist.win-amd64\egg\pysqlcipher3
    copying build\lib.win-amd64-3.7\pysqlcipher3\dump.py -> build\bdist.win-amd64\egg\pysqlcipher3
    creating build\bdist.win-amd64\egg\pysqlcipher3\test
    creating build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\dbapi.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\dump.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\factory.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\hooks.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\regression.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\sqlcipher.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\transactions.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\types.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\userfunctions.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\python3\__init__.py -> build\bdist.win-amd64\egg\pysqlcipher3\test\python3
    copying build\lib.win-amd64-3.7\pysqlcipher3\test\__init__.py -> build\bdist.win-amd64\egg\pysqlcipher3\test
    copying build\lib.win-amd64-3.7\pysqlcipher3\_sqlite3.cp37-win_amd64.pyd -> build\bdist.win-amd64\egg\pysqlcipher3
    copying build\lib.win-amd64-3.7\pysqlcipher3\__init__.py -> build\bdist.win-amd64\egg\pysqlcipher3
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\dbapi2.py to dbapi2.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\dump.py to dump.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\dbapi.py to dbapi.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\dump.py to dump.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\factory.py to factory.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\hooks.py to hooks.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\regression.py to regression.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\sqlcipher.py to sqlcipher.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\transactions.py to transactions.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\types.py to types.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\userfunctions.py to userfunctions.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\python3\__init__.py to __init__.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\test\__init__.py to __init__.cpython-37.pyc
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\__init__.py to __init__.cpython-37.pyc
    creating stub loader for pysqlcipher3\_sqlite3.cp37-win_amd64.pyd
    byte-compiling build\bdist.win-amd64\egg\pysqlcipher3\_sqlite3.py to _sqlite3.cpython-37.pyc
    creating build\bdist.win-amd64\egg\EGG-INFO
    copying pysqlcipher3.egg-info\PKG-INFO -> build\bdist.win-amd64\egg\EGG-INFO
    copying pysqlcipher3.egg-info\SOURCES.txt -> build\bdist.win-amd64\egg\EGG-INFO
    copying pysqlcipher3.egg-info\dependency_links.txt -> build\bdist.win-amd64\egg\EGG-INFO
    copying pysqlcipher3.egg-info\top_level.txt -> build\bdist.win-amd64\egg\EGG-INFO
    writing build\bdist.win-amd64\egg\EGG-INFO\native_libs.txt
    zip_safe flag not set; analyzing archive contents...
    pysqlcipher3.__pycache__._sqlite3.cpython-37: module references __file__
    creating dist
    creating 'dist\pysqlcipher3-1.0.3-py3.7-win-amd64.egg' and adding 'build\bdist.win-amd64\egg' to it
    removing 'build\bdist.win-amd64\egg' (and everything under it)
    Processing pysqlcipher3-1.0.3-py3.7-win-amd64.egg
    creating d:\work\python37\lib\site-packages\pysqlcipher3-1.0.3-py3.7-win-amd64.egg
    Extracting pysqlcipher3-1.0.3-py3.7-win-amd64.egg to d:\work\python37\lib\site-packages
    Adding pysqlcipher3 1.0.3 to easy-install.pth file

    Installed d:\work\python37\lib\site-packages\pysqlcipher3-1.0.3-py3.7-win-amd64.egg
    Processing dependencies for pysqlcipher3==1.0.3
    Finished processing dependencies for pysqlcipher3==1.0.3

    中间过程如果执行有差错,可以clean一下再重试:

    1
    D:\MyDocs\Desktop\pysqlcipher3>python setup.py clean

测试

至此pysqlcipher3编译安装完毕,写个程序测试一下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
from pysqlcipher3 import dbapi2 as sqlite

conn1 = sqlite.connect("test.db")
c1 = conn1.cursor()
c1.execute("PRAGMA key='123456'")
c1.execute("""create table stocks (date text, trans text, symbol text, qty real, price real)""")
c1.execute("""insert into stocks values ('2006-01-05','BUY','RHAT',100,35.14)""")
conn1.commit()
c1.close()

conn2 = sqlite.connect("test.db")
c2 = conn2.cursor()
c2.execute("PRAGMA key='123456'")
print(c2.execute("""select * from stocks""").fetchall())
c2.close()

结果

1
2
3
4
5
D:\work\Python37\python.exe
C:/Users/caipi/IdeaProjects/wechat_db_decrypt/test.py [('2006-01-05',
'BUY', 'RHAT', 100.0, 35.14)]

Process finished with exit code 0

也可能执行失败,提示

1
2
3
4
5
6
7
8
D:\work\Python37\python.exe
C:/Users/caipi/IdeaProjects/wechat_db_decrypt/test.py Traceback (most
recent call last): File
"C:/Users/caipi/IdeaProjects/wechat_db_decrypt/test.py", line 1, in
<module>
from pysqlcipher3 import dbapi2 as sqlite File "D:\work\Python37\lib\site-packages\pysqlcipher3-1.0.3-py3.7-win-amd64.egg\pysqlcipher3\dbapi2.py",
line 33, in <module>
from pysqlcipher3._sqlite3 import * ImportError: DLL load failed: 找不到指定的模块。

最有可能的原因是上面提到的 OpenSSL 问题,没有拷贝到 Windows 系统目录,或者没有将 OpenSSL-Win64\bin 目录增加到环境变量PATH。

关于sqlcipher版本问题

编译完成后,自己测试创建一个db再读取没问题,但可能打开其他现成的加密db会失败,提示file is not a database,实际错误是解密失败,最大的可能性是我们clone的sqlcipher当前是4.x版本,而要打开的db是由3.x版本创建的。

参考SQLCipher 4的更新说明

SQLCipher Core

  • Default page size for databases increased to 4096 bytes (up from 1024)
  • Default PBKDF2 iterations increased to 256,000 (up from 64,000)
  • Default KDF algorithm is now PBKDF2-HMAC-SHA512 (from PBKDF2-HMAC-SHA1)
  • Default HMAC algorithm is now HMAC-SHA512 (from HMAC-SHA1)
  • …

使用最新版本的DB Browser for SQLCipher也无法打开测试代码创建的test.db,原因也是如此

image.png-38.3kB

想要使用Python打开sqlcipher3版本的数据库,可以在调用代码里指定加密算法

1
2
3
4
5
...
cur.execute("PRAGMA cipher_page_size = 1024")
cur.execute("PRAGMA cipher_kdf_algorithm = PBKDF2_HMAC_SHA1")
cur.execute("PRAGMA cipher_hmac_algorithm = HMAC_SHA1")
...

如果完全不需要sqlcipher4的支持,可以在第5步时指定切换到sqlcipher3编译(目前最新的是3.4.2版本):

1
2
D:\MyDocs\Desktop>git clone https://github.com/sqlcipher/sqlcipher.git
D:\MyDocs\Desktop>git checkout tags/v3.4.2

这样生成的test.db也可以用DB Browser for SQLCipher来打开编辑了。

试遍淘宝手机辅助按键,看谁才是真·吃鸡神器

发表于 2018-06-26 | 更新于 2019-01-23 | 分类于 技术

手残党的怨念

本人多年FPS玩家,水平虽然不高,但从Delta Force玩到CS、COD、守望先锋、绝地求生,自认为游戏见识还算丰富。自从Steam吃鸡火爆,国内各厂争先往手机端移植,一开始我是不看好的:不相信通过触摸屏也能还原FPS的体验,因为通常手游最多只能用左右手各一根手指操作,而FPS需要同时控制移动、视角、射击三个变量,必然操作不便。然而接下来很快被刺激战场打脸,这可能是手游史上将端游FPS还原得最好的一款游戏,提供了双射击键、陀螺仪、3D Touch,还有很方便的探头操作方案,这些设计让没有高性能PC的玩家也能很大程度上体验到吃鸡的乐趣。

随着对操作的熟悉和游戏理解的加深,很快发现搓屏的操作方式终究还是限制了我的战绩,主要两个问题:

  1. 被偷袭时,一紧张经常不能准确地按中射击键反击,气得想摔手机。
  2. 通常习惯左手按射击键,方便精准瞄准,但交火时左手占用无法左右横移,发挥不了身法优势,而这在PC或主机FPS游戏中只是基本操作。

当时想到解决这两个问题最好的方案就是键鼠,也发现已经有PC模拟器提供了现成解决方案,但失去了手机移动优势,还不如玩端游吃鸡,而且光子也很快发宣布将模拟器玩家隔离排位。

第二个方案就是手柄。认真调研后购买了价格最贵的飞智八爪鱼,体验了半天就彻底放弃。首次配置极其繁琐,上手困难,按键手感奇差,转身速度和瞄准精度都不如手机搓,虽然也提供了陀螺仪瞄准,但灵敏度和精度也远不如手机原生陀螺仪。

第三个方案就是辅助按键了,也是本文的主角。之前偶然看到一个用口香糖铝箔制作辅助射击键的视频,心想到这么简单的原理,应该会有商家做出成熟的产品吧。在万能的淘宝一找果然有很多款,设计各不相同,价位大多十几二十元。

image.png-722.8kB

在购买了一款尝试后,虽然发现有诸多不便,但的确能显著提升射击速度,很可能是最有效的方案。为了找到最好用的那款辅助按键,我干脆把淘宝热门的款式都买了回来(反正加起来也没到一个手柄钱),并记录下各自的体验结果,在这里分享给大家。

辅助按键的原理

先说一下手机电容屏的原理:

一片四边形绝缘片的单面被涂上传导层。给传导层施加微小的电压后,产生了一个均匀的静电场。当一个导体,如人的手指接触到没有涂层的(绝缘)表面时,一个电容就动态的形成了。感应器的控制器将能够从绝缘片的四个角测量到电容量,从而能够得知触摸的位置。

摘自维基百科:电容式感应

正常操作手机游戏,需要眼睛的协助才能准确点击中屏幕上的射击、瞄准键,但拇指只有两根,想同时操作移动、视角、射击至少需要三根手指。利用电容屏导电的原理,通过在屏幕按键位置固定两个电极,将电极另一端固定在手机的上沿靠近左右手食指的位置,食指按下电极时相当于触摸了屏幕上对应的虚拟按键,而且左右食指只各自负责一个按键(射击与开镜),触发距离很小,完全可以盲操。这使得我们可以用最多四只手指同时操作游戏,分别实现移动、视角、开镜、射击,互相独立,分工和主流游戏机手柄一样,达到效率最高。

提前说明一个辅助按键的缺点:按键安装上手机之后本身就会破坏屏幕电感的平衡,手机可能误以为已经有两根手指压在屏幕上而产生“误触”,这时候再点击物理按键是无法模拟点击屏幕的。因此,安装好按键后必须先对手机进行锁屏(熄屏)再重新解锁(亮屏),这会对触摸定位算法进行重置,建立一个新的平衡,辅助按键才可以正常响应。初次体验辅助按键的用户往往没注意到商品页面上的说明(如我),以为买了个骗人玩意,也有不少淘宝卖家因此获得了糟糕的商品评价。

考察标准

具体介绍每一款按键之前,先说一下考察的标准。在没接触之前,本以为做一款辅助按键很简单,后来发现要考虑的细节其实很多,这也是为什么淘宝上有多款不同的设计。

按重要性逐个说明:

  1. 可靠性

    正因为手指触屏易失误,所以才需要物理“外挂”来提升可靠性,灵敏度是一款按键最重要的指标,但太过灵敏的话又有误触风险(容易走火也是原生触屏操作的一大缺点),所以需要的是可靠的灵敏,开火的时候快速响应,停火的时候快速中止,跑毒的时候不易误触。

  2. 兼容性

    手机那么多型号,苹果/安卓、全面屏/非全面屏,带壳/不带壳、贴膜/不贴膜,是否容易安装和卸下,是否牢固稳定。

    有可能你期待满满的吃鸡神器收到后根本装不上手机,设计不良的辅助按键,轻可能夹坏贴膜、刮花屏幕,重可能损伤摄像头。

  3. 舒适性

    安装后按键位置是否合理,长期持握是否舒适,是否会遮挡太多屏幕内容,是否影响手指进行其他操作。

  4. 工艺性

    是否坚固耐久,是否精致美观,做工太差的产品,可能还没开始装机调试就开始怀疑自己很SB。

谁是终极神器?

开始进入正题,先晒下订单,然后按我的体验顺序逐个介绍,并会在每一个体验的感受中总结。

image.png-1225.5kB

image.png-14953.8kB

注意,我主要使用的手机是iPhoneX,也用iPhone 6 Plus及小米6进行了简单试用,仅仅是个人观点,不一定代表你手上机器的真正体验。


1. 原始经典款

这可能是手游吃鸡辅助按键的鼻祖,是2018春节前能在淘宝搜到的唯一款式。因为正在评估考察的时候朋友已经先下单了,就直接借来体验了一下,但最后并没有真正购买。

image.png-670kB

image.png-270.9kB

从细节图上可以看到吃鸡按键的基本结构:电容导电棉用于接触屏幕模拟手指,金属触点用于食指按压触发,金属导线连接导电棉与金属触点,通过三者实现指尖电场的延伸。

按键其他部分都是塑料,没有任何活动件,用塑料本身的弹性夹住手机。出于稳固需要,包括导电棉的一脚外共有四爪前后固定。

  • 可靠性:★★★★

    响应迅速可靠

    初代产品触点可能存在氧化问题,后期产品使用了紫铜触点改进

  • 兼容性:★★

    对手机厚度有要求。目前大多数手机的裸机可直接安装(如iPhone 6 Plus),对戴保护套且贴膜的手机较难兼容。而对iPhone X这样本来比较厚,且摄像头凸起还正好在左上方(横屏时)的手机则彻底无法安装。有人说把手机倒过来就不冲突摄像头了,确实是,但有带来了另外3个缺点。一、倒置横屏需要开启手机横竖屏重力感应,对于不需要这个功能的人(如我)在每次安装时又多了一步操作。二、iPhone X正常横持时辅助按键会包围左侧电源键,电源键在游戏进行中是不需要使用的,影响不大。倒置横持右侧辅助按键会包围音量控制键,音量在游戏过程中经常需要操作。三、边玩边充电的情况下,正常横持时充电线在右侧,影响开镜还可以忍受,倒置时充电线在左侧,影响射击不能忍受。

    二、iPhone正常横持时,充电口在右侧,右手负责

    双爪设计,多余的爪子对非全屏手机正好在屏幕外不影响视线,但在全面屏手机吃鸡时多余的爪分别会挡住队友名称和游戏地图,严重破坏游戏体验。

    安装位置与手机电源键或音量键(反向持握)冲突,对于安装后需要锁屏重置非常不便。另外稍用力按下可能触发锁屏/音量调节,导致成盒悲剧。

  • 舒适性:★★★

    触点位置在手机的顶部两角,待机与射击时时食指都需要保持一个弓形的姿势,长时间下来容易疲劳,在小屏手机上更加明显(因为侧边更短)。

  • 工艺性:★★

    存在毛边、接缝和裸露的导线,做工较简陋。

点评:创意与执行力值得敬佩。整体中规中矩,初代产品选用最稳妥的方案无可厚非,做到了“让一部分鸡友先用起来”。淘宝链接

2. 按键触摸双模款

使用螺丝调节压力固定,对保护膜和手机壳友好。

使用物理按键按压触发,便于手指待机时停放。提供按压与触摸双模式,左右键调换使用则方便切换为触摸触发。

image.png-264.4kB

image.png-405.1kB

image.png-194.9kB

  • 可靠性:★★★

    食指可停放在按键上待机,开镜射击响应快。

    按压阻尼偏大,导致手感不清晰,不易掌握触发力度,偶尔出现按下无触发。

    存在金属触点,容易腐蚀氧化,长久可靠性会下降。

  • 兼容性:★★★★☆

    最大支持厚度11mm,兼容所有手机,兼容全屏与非全屏。

    单爪设计,对屏幕遮挡极小。

    精心设计了顶部凹槽,完美防误触电源键。

    顶部全包围设计,安装后锁屏重置稍有不便。

  • 舒适性:★★★

    按键水平位置可调,按压式设计,食指悬停在手机上沿舒展自然。

    按键面积太小,阻尼偏大,导致手感差,也影响响应速度。

  • 工艺性:★★★☆

    集成了塑料、橡胶、铜、铝多种材质,工艺设计出彩,堆料扎实,但加工精度稍逊。

点评:优秀的创意与工艺设计,可惜按键手感功亏一篑,期待改进(加大按键面积,优化阻尼)。淘宝链接

3. 销量明星C9

单爪设计,预留一定空间嵌入手机,使用翻转扣挤压手机背面固定。

按键式,采用导电塑料作为手指电极,用塑料弯曲提供按键回弹。

可能是淘宝分销做得最成功的款式,众多店铺代理销售。

image.png-195.3kB

  • 可靠性:★★★★

    按键式的优点,食指自然停放待机,开镜射击响应快。

    按下时导电塑料与导电棉的接触不完全可靠,偶现无触发。

  • 兼容性:★★

    对手机厚度要求高,最大支持厚度8mm,不兼容较厚或带壳手机。iPhone 6 Plus裸机可使用,尝试上iPhone X时夹坏了我的玻璃膜,不敢再试。

    同样设计有顶部凹槽,防误触电源键。

  • 舒适性:★★★★☆

    待机悬停舒展自然,按键面积大,弹性适当,使用体验接近手柄。

  • 工艺性:★★★★

    设计简单巧妙,精细度较高。

点评:兼顾功能与成本的巧妙设计,可惜一体化结构带来的兼容性短板,对手机厚度有严格要求。淘宝链接

4. 无语米形

一体化单爪设计,通过弹簧加多个不同厚度的海绵垫片兼容不同手机。

专业的产品介绍页面,夸张的销量数字(可惜期望越大,失望也越大)。

image.png-279.1kB

image.png-154.3kB

image.png-143.7kB

  • 可靠性:★★

    手指直接按压一个尾端伸出来的不锈钢丝圈触发,触发可靠性OK。

    单爪固定设计加长度夸张的主体,安装在iPhone 6 Plus这种正常厚度手机上时,按键的一端容易绕单爪固定点为轴心产生滑动,是所有试验过的辅助按键中稳定性最差的一款。

  • 兼容性:★★★

    弹簧提供了一定的余量,通过随机附送的不同厚度的3M不干胶贴配合,最大可兼容厚度10mm的手机,iPhone X加手机壳也不在话下。

    顶部全包围设计,与锁屏激活操作存在冲突,用力按下主体时会传递到电源键导致游戏中锁屏。

  • 舒适性:★★

    触点不是按键也不是金属片,而是一个从主体中伸出7~8mm的U型的钢丝圈电极,手指按压在U型圈底部触发。钢丝直径0.5mm,按下后手指被顶出凹印,有明显不适感。

    安装位置固定,无法调节。

    触点位置在手机上沿两角,待机姿势极其别扭,时间稍长易疲劳。

  • 工艺性:★

    硬塑料廉价感明显;不对称设计和夸张比例带来奇怪的重心,永远无法在一个平面稳定摆放。

    应该是为了照顾部分非全屏手机两侧非屏幕区高度不一致在《终结者》这款游戏中不好适配的问题,设计了左键52mm、右侧59mm的长度。但面对全面屏对称屏手机越来越普及,《终结者》已凉的现在,这样不对称的设计极其丑陋。

点评:卖家秀和买家秀的惨痛教训。淘宝链接

5. 微动诱惑

双爪一体化,背面卡扣翻转用于固定;使用机械微动开关实现按键式触发,手感清晰。

image.png-370.8kB

image.png-206.6kB

  • 可靠性:★★★

    与鼠标按键一样,通过微动开关按下和释放产生清脆的咔哒声带来了清晰的反馈。但因为增加了微动开关,相比之前介绍的按键式额外增多了一个传导触点,可能带来更多的不稳定性。

  • 兼容性:★★★

    一体化设计的缺陷,兼容手机范围有限。勉强支持iPhone X不带壳,安装过程容易碎膜。这种依赖塑料弹性嵌住手机的按键,在插入过程中都容易顶压贴膜边缘,这是贴膜最脆弱的位置。

    窄爪对屏幕遮挡小,但双爪设计对全面屏不友好。

    顶部全包围设计,与锁屏激活操作存在冲突,用力按下主体时会传递到电源键导致游戏中锁屏。

  • 舒适性:★★

    可能由于微动装置体积较大,并没有设计在主体的上沿,而是附加在主体背面。这导致持握手机时食指不是自然包围手机边沿,而是呈一定角度上的斜错(如下图),这降低了持握的安全感,姿势也极容易疲劳。

    image.png-282.3kB

    通过压下不锈钢制的一个杠杆片触发微动,触发键程较大,反而对微动带来的优点产生了抵销。

    手指触点虽然做了一定的弧形弯折提高舒适度,但不锈钢片边缘切割锐利,未经打磨极其硌手。

  • 工艺性:★★

    塑料廉价感明显,触点切割锐利,工艺粗糙。

点评:机械微动开关是很好的创意,败在设计与工艺。淘宝链接

6. 平板也吃鸡

因为iPad的大屏幕更易发现和瞄准敌人,平时偶尔也会用iPad吃鸡,这款辅助按键就是专为iPad而设计。

不同于其他辅助按键设计,这款按键很像一个晾衣夹,用的时候直接夹在平板上。一个导电圆柱体既作为屏幕电极,同时也是手指电极。食指平时停放在夹子正面,射击时直接按压柱体的侧面来连导屏幕。

image.png-673.8kB

image.png-68.4kB

  • 可靠性:★★★

    电极简单可靠,响应灵敏。

    夹子力臂较长,无法提供足够的弹力,游戏过程中用例稍大就容易移位,导致开镜射击无响应。

  • 兼容性:★★☆

    理论上兼容所有平板,但夹子深度有限,在iPad上电极无法完全覆盖到屏幕区域,大约有1/4的电极落在屏幕外框,加上夹子弹力不足,稍稍一位移就功能失效。

  • 舒适性:★★☆

    一般持握iPad时食指通常放平板背面,但此套装置要求食指放屏幕正面,相当于用双手食指与中指夹住iPad,姿势与高玩们的四指操作非常接近,手残党感觉非常别扭,容易疲劳,

  • 工艺性:★★★★★

    主体塑料上镀有一层亲肤材质,带来了非常舒适的手感,各种边角圆滑光润,做工极其精致。

点评:相比起玩耍,更适合收藏。淘宝链接

7. 铁的教训款

试过这么多塑料结构后,突然想试试金属一体式的,这套设计简洁美观,屏幕遮挡少,应该会不错,然而……

image.png-511.3kB

  • 可靠性:☆
    在iPhone X和iPhone 6 Plus上完全无法触发,与卖家沟通后毫不惊讶表示给你退货,但懒得寄快递了。目前卖家共9个评价,其中1个中评和1个差评。
  • 兼容性:★★★
  • 舒适性:★★☆
  • 工艺性:★★☆

点评:不做太多评价,就当买了个教训。淘宝链接

8. 转角遇真爱

受上一款金属版伤害后继续寻觅,被这款价格所吸引,随便买了一对,没想遇到真爱。

image.png-329.2kB

  • 可靠性:★★★★☆

    结构简单,全部拆开也就是铝合金主体、海绵垫、固定螺丝、螺丝垫脚4个元件。铝合金主体展开的话(如果能)是十字结构,四瓣分别充当屏幕电极x1、手指电极x2、后背固定脚x1。手指按在主体任意位置都能够触发开镜/射击。

    一个小缺陷是是螺丝上的橡胶垫脚是用3M不干胶粘在螺丝上的,螺丝旋紧时本身会受到一定扭力,游戏过程中手指推移也可能导致脚垫松脱失去固定。解决办法是用一滴502来替代不干胶,一劳永逸。

  • 兼容性:★★★★☆

    按键主体不可形变,通过调整螺丝深浅顶住手机后背来固定,最高12mm的厚度理论上兼容所有手机,iPhone X + 贴膜 + 厚保护套不在话下。

    image.png-377.8kB

    主体内侧贴有一块5mm厚的海绵垫,一开始我认为这个设计很奇葩,装上手机像一双厚厚的松糕鞋。但随后发现这能分散手指压力,避免力量传导到电源键上触发锁屏。海绵垫形状跟主体一致呈8字形,内凹的区域正好给下面的电源键留出了一点点空间,于是可以在安装完毕后用指甲按到电源键,方便锁屏激活。这个矛盾的电源键竟然通过一块海绵垫解决,实在有点巧妙。

    虽然是单爪设计,但遮挡屏幕面积稍大,未能完美。

  • 舒适性:★★★★☆

    按键位置可调,食指自然围绕手机边沿,持握舒适稳固。

    按键面积适当,所有棱面都进行过打磨,按键操作舒适。

    左右键完全对称,安装方便。

  • 工艺性:★★★★

    按键主体加工整齐,漆面细致。结构简单,不易损坏。

    固定螺丝精细度稍逊,不干胶贴保护垫方案稳定性不足。

    第一次买的时候没的挑,收货后发现正面印刷的Logo非常不美观,后来复购了一对银色无Logo版本。

点评:无心插柳,简单的却是最好的。淘宝链接 拼多多链接

9. 金属收藏款

受到第6款失败刺激后与第7款同日购买,结构也类似。工艺极其优秀,甚至怀疑是整块CNC切削而来。

image.png-302.1kB

  • 可靠性:★★☆

    金属电极响应可靠,但后背爪与固定螺丝体积巨大,持握手机时一般中指贴在手机后背,游戏时中指容易碰触背爪或金属螺丝而误触发,哭笑不得。

  • 兼容性:★★★★

    左右位置可调,最大支持厚度11mm,兼容各种手机。

  • 舒适性:★★☆

    按键面积太小,金属棱角锋利,硌手。

  • 工艺性:★★★★★

    无论是主体还是螺丝,都精细漂亮,无可挑剔。

点评:一个华丽的鸡肋,我会好好收藏。淘宝链接

10. ZNNCO

这是评论区@一笑朋友极力推荐的,价格不贵16.9元一对包邮,我也下单了一副来体验。ZNNCO可能只是京东卖家的一个渠道号,淘宝上还有大量的无牌同款产品。

image.png-19.4kB

京东发货物流神速,凌晨下单当天即达。

image.png-664.3kB

外形与第3款C9很像,单爪一体化+卡口嵌入式,主体采用透明塑料,视觉上更精致。

触发结构非常巧妙,与C9完全不同。顶部是一副桥式对称按键,桥片两端分别卡在主体上,底部中心的突起被一片中央拱起的圆形金属簧片顶住,呈三点式临时固定。桥片两端都可以作为按键按下,压力传导至簧片,簧片先是提供按下的阻力,在反曲变形瞬间阻力会反向变成助力,迅速连通电路到底部的电极,这本身就是一个典型的微动开关结构。另外,所有的电路包括电极都是纯铜的薄片。

image.png-468.3kB

  • 可靠性:★★★☆

    我收到的两个按键其中一个很正常,而另一个不需要按下,只要手指触摸按键上的电极就会触发开枪。拆开后了解了它的结构原理,发现就是簧片底部的铜片弹起太高,直接接触簧片的底部导致了上下连通。重新调整了底部的铜片高度后问题解决,这个问题估计会比较普遍,显然与设计和装配工艺有关。

    3层金属带来2个开关点,随着铜电极的氧化和簧片反复弯折积累的金属疲劳,预计未来的可靠性会显著下降。

  • 兼容性:★★★☆

    卡口结构与第5款非常相似,在塑料主体上实现了较大的兼容性,最佳厚度是8mm左右手机,但iPhone X带壳带膜(10mm)可以非常勉强地装配上去(注意碎膜风险)。而且这种透明塑料应该脆性比较大,操作不当容易断裂,翻京东的评价得到了证实。

    左右对称,位置可调;单爪设计,对屏幕遮挡小,好评。

  • 舒适性:★★★★☆

    待机悬停舒展自然,按键面积大,弹性适当,使用体验接近手柄。

    键程稍涩,随着簧片老化,会逐渐严重。

  • 工艺性:★★★☆

    设计巧妙,外观讨喜,但用料与工艺精度一般,从实拍图上已经可以看到铜片的氧化情况,对寿命不太有信心。

点评:价格厚道,可以尝试,不差钱可以多买几副。京东连接

11. 第三代金属按键版

这是一位知友@千城暮雪给我私信发来的体验,按天猫页面的描述应该是第1款的三代升级版本,获得知友同意后,我把它补充进来,供大家参考。

image.png-598.2kB

这款按键采用了两个杠杆联动作为触发,因为安装时没有导电体在屏幕上,按下后模拟手指点击,所以安装完不需要重新亮屏。Mix的id设计大家都知道,我习惯把下巴放左边玩,能够完美的避开音量键,这款按键屏幕上要卡两个地方做支撑,一个是模拟按键的,需要放到射击键上,另外一边为了防滑用了硅胶,所以我们可以在不用的时候把按键往上面一拉,这样就能完美的不挡住屏幕了。

  • 可靠性:★★★★

    因为使用了铜上镀铬的处理。使用了两个联动杠杆。虽然杠杆用了两个,可能会降低可靠性,但是我仍然能给他四星,因为表面镀了铬没那么容易氧化。我用了差不多一个月了,到现在为止没有出现过失灵或者走火的现象。

  • 兼容性:暂缺

    本人手机裸奔,所以不在乎卡不卡的上的问题,不过Mix2的厚度大家也都知道。应该能兼容主流的大部分手机的。

    这个按钮目前我发现的缺点就是,当你开枪的时候,你不知道到底有没有按下去,没有鼠标按键的那种段落感。

  • 舒适性:暂缺

    这个按键金属部分使用了铸造的铜构件。表面看起来是镀铬处理,所以手感十分的顺滑,不会像金属片那样割到手。按键位置比较适中,做了圆弧处理。

  • 工艺性:暂缺

作者点评:通过杠杆结构将开关触点移到离屏幕最近的地方,避免了安装后需要重新激活屏幕的问题,这是非常聪明的设计。但双爪结构会带来对全屏的遮挡,也因为双爪结构按键只能在最顶两端,持握不舒适。作者尝试在淘宝找到了它的单爪版本,正在物流途中,回头继续补充。天猫链接

12. 单脚透明杠杆式

这是看了知友的第11款评价后,作者另行购买的改进版。基本原理和结构都与第10款一样,但从双脚变为了单脚。理论上与第10款性能相当,但经过我自己的亲手测试,感受更真切。

image.png-542.3kB

image.png-362.9kB

双杠杆联动结构,平常没有任何电极与屏幕接触,因此完全不存在锁屏重置的麻烦。按下扳机时(这个手感相比按键确实更像扳机),抬起杠杆1的另一端,顶起杠杆2,杠杆2的另一端是电极,被撬动往下压接触到屏幕,完成整个感应电路。

  • 可靠性:★★☆

    杠杆联动设计解决了锁屏重置问题,但带来了非常机械的手感,按下的前半段有虚位而后半段艰涩。有时轻轻一按即可触发射击,有时却需要更大的大量,缺乏清晰的手感,无法提供强烈的射击信心。@千城暮雪在第10款的兼容性部分也有提到。

  • 兼容性:★★★

    塑料嵌入式,勉强可支持iPhone X带壳,意味着可兼容市面绝大多数手机。

    单脚设计避免了双脚带来的额外遮蔽,但单脚塑料结构在夹住双面玻璃手机(iPhone X)时无法提供稳定的固定,会出现类似第4款的晃动,极其影响游戏体验。其他材质手机应该有改善。

  • 舒适性:★★★★

    按键水平位置可任意调整,按键圆润不硌手。

    全物理联动,需要按键力气偏大,久易疲劳。

  • 工艺性:★★★

    设计巧妙,既是机械结构,也是电路结构。

    透明材质讨喜,防滑考虑不足。

点评:设计巧妙,为电子游戏提供了扳机手感,成也在此,亏也在此。淘宝链接

13. 鸡霸·屏后扳机式

这是评论区@悲伤的闪光推荐的产品,基本原理与第11、12款一样,双杠杆联动、扳机手感,但第一节杠杆的方向不是水平的,而是垂直于屏幕方向,因此扳机位于屏幕背后。

image.png-455.7kB

image.png-155.1kB

由于大部分机构在屏后,装上手机后,这是目前所有按键中屏上面积最小的一款。

  • 可靠性:★★☆

    与第12款同样的原理,也存在同样的问题,而且第一节杠杆是垂直屏幕,由于重力的原因平常处于下垂状态导致了近3mm的虚位,按下3mm后须要再进一步用力才可触发第二节杠杆触点触屏,手感极其模糊。

  • 兼容性:★★☆

    最大支持9mm厚度手机,只能支持不戴壳的iPhone X,但由于结构以及纯塑料材质的原因,无论是iPhone X还是小米6,安装后都容易发生滑动。商家随机附送了两个防滑贴纸,有一定效果,但未能彻底解决。

    对于iPhone X这样两面光滑的手机,必须倒持安装,避开锁屏与音量键一侧,否则极其容易按下时触发锁屏/音量键。

  • 舒适性:★★☆

    在第5款的介绍中我提到了屏后按键会带来持握不稳定以及疲劳,再一次得到了验证。为了确定不是我自己手残,我观察了周围6个以上朋友玩吃鸡的姿势,无一不是双手食指呈90度卡在屏幕顶部两角,以提供最大的稳定性。屏后扳机每次按下时会产生一个从屏幕部朝向自己的作用力,带来手机一定的翻转,为了减小翻转幅度又不得不将双手拇指更用力顶在屏幕上,这降低了拇指动作的精确性,时间一长也带来了疲劳。XBox与PS手柄之所以能将按钮置于手柄背面,是因为游戏机手柄提供了两个握把,按压背部按键时,通过抓紧握把可以完全保持住手柄水平稳定性。而在手机上,其余的手指只能提供简单的支撑,难以水平稳定。因此,以后不会再尝试屏后按键式了。

    需要按键力气偏大,久易疲劳。

  • 工艺性:★★★☆

    屏后扳机很有创意,既是机械结构,也是电路结构。

    透明材质讨喜,防滑考虑不足。

点评:好的创意没有带来好的体验,可惜可惜。淘宝链接


总结

作为一个物理“外挂”,吃鸡辅助按键原理简单,但要兼容不同的手机、不同的游戏、乃至不同的用户习惯,挑战并不简单。做好了是帮助,没做好就是累赘,这很需要创意、设计与工艺的完美结合。

合适的产品能够提升战绩,但目前无论哪一款辅助按键,都有以下所有的缺点:

  1. 携带累赘,拆卸繁琐
  2. 大部分产品初次安装后须要锁屏激活才可使用
  3. 阻碍手机侧面物理按键的操作:电源、音量
  4. 存在视野遮蔽
  5. 存在操作阻碍,可能影响跳伞跟随,语音,视野等屏幕上半区的小操作
  6. 必须将开镜、射击键设置在屏幕顶部,正好也是横屏时Push通知弹出的区域,这时候要是按开枪可能就进微信了

想尝鲜的朋友,请提前做好心理预期。

最后分享一个我用辅助按键操作吃鸡的小视频:

瘾大时间少,水平一般,目前星钻,但六种模式基本都有S+/SS,80以上的评分,有时间应该能上皇冠,大神们看了轻点吐槽。

答网友问

评论区不少疑问,我更新统一回答在这里。

到底哪款好?

文章的目的尽可能全面的介绍我用过的这些玩意,给想尝试的同学一些信息。但每个人使用习惯不同,每人手机也不同,我在意的地方你可能不在意,在我手机上不方便在你手机可能没问题,而且目前所有的按键都不完美,直接给一个推荐是不太负责的。我个人常用的是第8款,觉得游戏体验还不错,缺点也还能接受。目前正在体验第10款,是评论区一位朋友推荐的,体验也很好,解决了第8款的一些缺点,但也有它的新问题。

这里也列一下我个人的选择标准,结合上面各款的案例,各位的理解应该会更准确。

  • 兼容性必须满足,装不上就只能送垃圾桶。最好是不需要倒置才能安装,安装后一定不能容易误触电源键,要出人命的。
  • 可靠性必须满足,这一方结构越简单越可靠,金属触摸款完全不存在该问题,按键款由于多了电路开关,存在触电氧化问题,可靠性会逐渐降低。
  • 持握舒适度。必须保证按键位置在手机上沿,持握更舒适,按压时也不影响水平稳定性。有时一玩就两个小时,持握姿势别扭、端不稳手机会手指发僵,有这耐力不如去苦练三指四指。
  • 按键舒适度。手指触点必须光滑、宽大。理论上按键式会提供更好的反馈,手指自然悬停在按键上,也能提升持握舒适度和响应时间,但按键阻尼的微调是门技术活,用料不当的话弹性元件还存在老化问题,而成本只有几块钱又只能选择廉价方案……
  • 安装便利度。螺丝式固定式安装稍麻烦,但兼容性广。弹性嵌入式安装相对简便,但要特别小心手机插入时易碎膜。两者各有优劣。
  • 屏幕遮挡。应越小越好,不管是不是全面屏手机,只选择单爪式。大多数单爪式都是左右对称设计,安装更方便且水平方向上位置可调整,能找到个人最舒适的位置。
  • 单个 or 双个?可以只安装一个左键用于开枪,但我仍推荐用双键模式,缩短开镜开枪时间。
  • 工艺,实用、不丑陋即可。

以我的标准,给了3星的选项表示还能接受,但有些扣分项是因为我的iPhone X特征,你可以根据自己手机情况参考评分。

最后购买之前,你可以仔细观察一下自己平常是用什么姿势持握手机游戏,尤其是食指一般放在哪里。再想象一下如果买了某款按键,它会安装在你手机上的什么位置,安装后持握是什么姿势,食指是否能够灵活操作,持机是否稳定。总之好的辅助按键应该让你在游戏的时候忘记它,把注意力全部投入到战场上,而不是让你觉得是在为了战绩而忍受。

有3D Touch还需要这个?

3D Touch只支持部分设备,手机不支持的朋友没得选。

刺激战场在支持3D Touch的版本发布后我立即尝试过,但也很快放弃了。我认为跟真枪操作一样,瞄准与射击操作应该是分离开的,这样最自然,效率也最高。3D Touch操作模式要求右手拇指兼顾瞄准和射击,在刚枪走位时确实方便,但远程狙击时需要精确操作,瞄准(移动)和射击(按下)动作可能互相干扰,无法提供信心。

另外,人和人的差异确实是存在的,我玩游戏的时候容易兴奋,手指力量忽大忽小,3D Touch模式走火率奇高。

为什么用这个?我两指/四指操作比这6多了

这个问题不是很有争论的必要,为什么大家都有眼睛而有的人却要戴眼镜?每个人情况不同,接触游戏时间不同,玩游戏的目的也不一样,我的目的是在工作之余得到快乐和放松,不是做主播打职业上天梯。辅助按键能让我专注在游戏本身,而不是如何搓屏幕上,我觉得更适合我而已。

发我的游戏视频只是一个小演示,不是炫耀技术。发我的游戏视频只是一个小演示,不是炫耀技术。觉得自己不用按键水平高的朋友,欢迎回答这题《绝地求生:刺激战场》有哪些吃鸡技巧?,不用在本文评论浪费时间。

辅助按键算不算开挂?

我对开挂的定义是使用电子设备通过软件或硬件手段,读取或修改游戏数据,而实现游戏正常规则之外的行为。

辅助按键没有外接其他的电子设备,没有任何数据的读取和修改,只是实现了人类肢体的延伸。就像我们现在不会说赤裸才是人类,而指责穿衣穿鞋的人不是人。

对于手游来说,物理上的绝对公平是不存在的,苹果安卓、大屏小屏,性能和视觉的表现就不一样。游戏本身还给苹果手机提供了独有的3D Touch支持,说明官方也对目前的射击操作也不满意,希望能用尽硬件的潜能,给玩家提供方便。即使对于模拟器+键鼠游戏,腾讯官方也没定性为开挂,甚至提供了官方模拟器支持,但是心里过意不去,而做了匹配隔离。放大到整个电子游戏的领域,有条件的玩家追逐性能更强的CPU显卡、更大更高刷新率的显示器、更精准的鼠标、更精准的耳机,和普通的玩家相比,这也不能算是开挂吧?

辅助按键合理优化了手指分工,让玩家可以更专注在游戏而不是操作冲突上,若是发展足够好,出现了更完美的装置,会得到腾讯的官方推荐也不一定。

还是觉得不公平的话就向腾讯举报吧,腾讯只要发篇公告给辅助按键下定论我就删文章。官方要想屏蔽此“外挂”也很容易,下一个版本禁止射击瞄准按钮放置在屏幕上半区,所有按钮就全部做废了。

声明

  • 以上的评价完全出于个人的主观体验,不代表其他人的操作习惯与感受。
  • 所有结果仅代表当时购买的商家版本或产品个体,不代表其他外观类似或后续改进版本。
  • 大部分图片来源于淘宝介绍,页面链接附在各款点评尾部,侵删。

小程序周记

发表于 2017-01-17 | 更新于 2018-05-24 | 分类于 技术

截止今日,微信小程序正式开放一周。作为一个参与者,同时也是观察者,我来回顾一下这周微信小程序见闻与体验。

前夜

1月8日,小程序发布前夜。我加入的两个小程序微信群开始热闹起来,大家纷纷猜测小程序究竟会当夜开放还是次日开放,或者是延期。有部分觉悟慢的同学还在临时抱佛脚,问一些很基础的问题。我当时猜测应该会等到9号白天上班后发布,理由是系统太庞大,夜里发布如果出了问题,可能不好找人解决。

9日0点,群里突然炸开,连续出现了小程序的分享名片,微信小程序踩着0点正式开放了!捂着热辣辣的脸,我只能佩服微信团队艺高胆大,半夜发布意味着整个鹅厂与此相关的员工都在待命。

匆忙打开电脑进入小程序后台,原来不可用的发布按钮已经可以点击了,接下来扫描二维码确认身份,发布了我的小程序「100房贷助手」几天前的已过审版本,然后又把最近提的一个体验版本提交了审核。由于微信审核的不可测原理,估计很多开发者都和我一样:尽早提审了第一个版本来确保赶上9号的发布,等到通过审核时,第二个版本也准备好了,只能Hold着等首个版本发出后再提。

微信群里越来越热,大家都在发自己的小程序名片,也分享在别处看到的小程序,还有抱着不同目的的人迅速组织了更多的微信群,我进了两三个,质量都不高。这两天读了一篇某个小程序项目团队的分享,说他们当晚加了200多个微信群和300多个QQ群来做产品曝光,这确实给我上了一课。

微信半夜小程序发布的好处是夜里用户量少,对系统冲击也少。让一批开发者和IT媒体们提前体验正好相当于灰度,也能趁天亮前有时间做些调整。更大的好处是:大多数小程序开发者都在等零点可能发布,媒体们也在摩拳擦掌,等普通用户们第二天起床处于信息饥饿状态时,新鲜的小程序资讯正好送上。

发布日

9日早晨,我起床注意到的第一条消息不是新闻,而是昨晚提交的版本已经审核通过的通知。
image_1b6jp9kru1tdl36j15lfrsokph9.png-90.6kB
之前两次审核分别用了6天值1天,这次竟然8小时神速过审,应该是微信预料了发布日的拥挤,安排了加班甚至是通宵在处理审核。

我擦了擦眼睛,迅速进行了发布。同时注意到,不同于首个版本的发布即可见,当已经有旧版本在线上时,新版本发布大概要延后3分钟生效。当然这比我们传统的APP发布要等待用户逐渐升级快速多了。

媒体果然爆炸了,朋友圈和知乎里到处是小程序的话题。得益于赶上了首批发布,我在几个微信群里做了入口分享,而且发布的前几天我在知晓程序的小程序商店(minapp.com)里提交了产品介绍。「100房贷助手」在当天很多小程序新闻稿中得到了曝光,后台监控到不断有新用户进来体验,为此我赶紧多加了一个服务节点避免过载。

其实首日发布的小程序并不多,微信在9月份开放了200个小程序内测名额,这些公司也成了首日为微信小程序站台的主体。我个人看来,除了通过微信分享卡片式的小程序页面能提升一些体验,其他惊喜并不多,很少有H5做不到只能小程序才能完成的场景。

更大的尴尬是:越有影响力的大厂们越能更早开发出更完善的小程序,也有更大的吸引力来让用户体验他们的小程序。但往往这样的大厂都是通过线上来变现的,当把用户吸引进了一个他们无法变现的小程序黑洞中,那自己也就没了生路。很多低频的APP被用户卸载,这让厂家很心痛,但却合理至极。

后续

第一天结束时媒体们傻眼了,昨天通宵赶文章还写微信即将要统治手机,看了一天下来发现不是这么回事,只能拿点段子交差。

接下来几天小程序热度明显下降,开有有少数公司停止了微信小程序的服务,还有部分类目被监管叫停。现在又有媒体出来泼冷水了,嘲笑微信没格局不开放。

其实微信也很委屈,本来期望的场景是线下,但反应最快传播也最快的总是线上,他们来了不爽就走。而线下的企业反应慢一些,服务铺开也需要时间,这需要更多的耐心来栽培。媒体自作多情,怪我咯?

数据分享

目前在小程序后台已经可以看到一周的数据统计,拿「100房贷助手」两个数据做一个简单的解读。

image_1b6k0bi911m9iehh1j2d1gtf4qi13.png-81.7kB

第一天因为赶上首发名单得到了不错的曝光,用户量较高,但第二天数据则出现大幅下降,直到第6、7天开始趋稳。对于一个没有持续投放的小工具产品来说,这个趋势是很正常的。但这无疑也吻合了微信小程序的热度,即5天后该来尝鲜的用户已经来得差不多了。

image_1b6k19kct1j0d8ng1gl0oek4v51g.png-173.3kB

以上是小程序的百度指数,趋势接近。

虽然大部分用户是尝鲜游客,而且其中大部分并没有真正的使用(无有效数据录入),但也值得高兴。正是因为程序赶上了首发,获得了一定的曝光,才带来的这波“蜜蜂”。这些尝鲜的用户会帮忙分享给有需要的朋友,以后自已有需求了也可能再来。

另一个数据是平均停留时长
image_1b6m50srbuqektnr1nob1166e9.png-86kB
总体在缓慢增长,说明用户开始在正在的使用产品,这是好的现象。

微信可能在用完即走这个概念上走太极端了,后台竟然不支持最关键的用户存留分析,希望未来能够加入。

总结

一点经验和教训,如果再重来一次,怎么低成本让小程序在发布首日后获得更多用户呢?

  1. 前期和发布日的大范围分享、投递。这会带来首批媒体稿中较高的曝光。
  2. 精美图标 + 有趣的名字。最好让人一看到就痒,产品曝光后更容易被尝鲜客试用。
  3. 有趣的内容,促使用户强烈的分享冲动(我相信分享是未来小程序的革命级特性)。
  4. 持续的价值 + 精美的制作。必须有持续的价值才能长久,精美制作有助于第二波的曝光与用户分享。

最后再自问自答一次:小程序有没有红利?
没有通常意义的流量红利,只能算一次热点事件,而且已经结束了。我相信更长远的红利是有的,可能需要等待下一个杀手级小程序的引爆。

小程序「100房贷助手」诞生记

发表于 2017-01-10 | 更新于 2018-05-24 | 分类于 项目

把自己的爱好作为职业是怎么样的体验?

知乎有很多类似的讨论,我算是很符合要求的一人吧。从高中开始,编程就是我的爱好,因为爱好,选择了大学专业,选择了最终的职业。

做自己喜欢的事当然开心,但职业中的选择有限,很多的时候只能重复无聊或执行并不认同的工作。累觉不爱的时候就得找点真心想做的项目来弥补一下,所以对我来说编程既是工作,也是消遣。

11年的时候由于自己有需求,写了一个Excel版贷款计算器,解决了利率变更和提前还款计算两个痛点,程序发布在网上也收获了不少用户的好评。但现在已经是移动互联网时代,经常只是想看一眼数据却得掏出PC和Excel这种重武器,还是不太方便,如果改成APP就好了。我把这个想法告诉了我的用户,他们也表示了很大的期待。

前阵子学习Android的新语言Kotlin,正好拿这个项目练手。Kotlin很赞,我很快上手并完成了核心算法,开始写界面。然后微信小程序来了,经过短暂的了解,我决定转向用小程序来实现。

为什么用小程序?

能力上,小程序基于阉割的H5,但微信提供了丰富的组件和API并保证了足够的性能,体验上和原生应用几乎无异,足够支持大部分的功能型应用。

成本上,它天生解决了跨平台的问题,意味着开发工作量可以减少一半,或者开发人员可以减掉一半。

交付上,有微信这个国民应用做Runtime,小程序只需要打包核心的代码逻辑,可以做到秒下秒开,将传统的APP扫码下载安装过程中的流失减到最低。直接发布的特性同时也解决了传统APP多平台、多版本兼容的问题。

推广上,微信已经占有了线上(消息)和线下(二维码)最大的渠道和入口,传统应用都不可避免要支持分享到微信和微信扫码。而小程序天然内置在微信中,基于微信好友和群的现成关系,很容易被传播分享。

以上都是我们传统APP开发者多年梦寐以求的特性,虽然小程序也有很多限制和不足,但对于我要做的这个小工具,它是完美的选择。

我能收获什么?

我不打算在最短的时间内把它搞定然后不管,否则这比赶工作还更无趣,我更希望把它当做一次有趣的实践,尽可能体验从0到1这个过程中相关的一切。

JavaScript是现在最活跃的编程语言,不仅跨过了Web页和服务端,近一年大热的React Native和Weex已经开始攻占移动端的地盘。移动端开发者如果还不主动了解,那就太迟钝了。从小程序入门,正好是一个机会。

小程序是微信近两年最大的动作,目标和特性都昭示了巨大的野心。它究竟能做到什么程度,未来会如何发展,只有参与了才有可靠的判断。

工作中我负责客户端,跟产品磨跟UI磨跟后端跟测试磨,大量的时间用在沟通和等待上,最终的交付也有很多不甘的妥协。这次我一人全栈,终于有机会做一个只让自己满意的产品,顺便体验一下不同职能的思考,对未来工作也有益处。

从未接触过产品的运营和推广,想在小程序的生态中探索一下盈利模式。先定一个小目标:收回成本!

张小龙对微信的寄托是“做一款伟大的产品取悦自己”,不知道此生我有没有这样的机会,至少目前我还可以做一款满意的小程序取悦自己。

「100房贷助手」的目标

买房是成家的必经之路,贷款又是买房的必经之路,起码中国如此。我经历过在银行办贷款签几十个名字的激动与担忧,合同还没看清楚就欠了上百万的负债,每月省吃俭用担心破产,央行降息让我暗暗开心,好不容易存了点钱去提前还款,又被银行大姐问到蒙圈。直到我认真研究了一下贷款的机制,开启了对理财的新认识。

我将我对贷款的知识与经验,装进这个小程序,并赋予它随时访问,轻松分享的能力。希望这个小工具,能帮助要购房和已购房的年轻人做点决策,清楚掌握自己的债务情况,做好财务规划,维持信用。

目前已经完成了基础的功能,还在继续打磨。如果你有更多的需要和建议,可以给我反馈。

谢谢!


准备贷款,想知道能承受多高的额度,月供多少。

已经贷款,央行宣布利息下/上调xx点,想知道月供会如何变化。

提前还款,想知道能缩短多少期限,节约多少利息。

用100房贷助手,让一切简单!

gh_1786c7d53423_258.jpg-29.7kB

我看微信小程序

发表于 2016-12-21 | 更新于 2018-05-24 | 分类于 技术

今年的互联网媒体们可能不太容易,大行业不景气,风投退缩,巨头抱团,新概念泡沫,没什么话题好挖掘。9月,微信宣布小程序的概念,开始内测,媒体们仿佛鲨鱼闻到血,东西还没看见就炸开了锅,漫天评论:“微信要成操作系统了”、“没必要再开发APP了”、“H5要一统天下了”……

技术圈子也被点炸,这两年iOS和Android系统趋于稳定,大家终于踩完了坑开始琢磨造点新轮子,突然发现又要被前端抢饭碗,这怎么坐得住。

我对此也挺感兴趣,之前一直想业余做个贷款计算的小APP,又嫌兼顾iOS和Android麻烦一直没动手。小程序如果真能跨平台,这是最好的时机,正好也了解一下这项可能要“抢饭碗”的技术。

11月,微信开始小程序公测,经过了一番波折的注册与开发,目前我的程序已经通过审核,我也算对这个新平台有了真切的认识,可以谈谈看法了。

小程序与微信

先说结论:短期来看,小程序对于微信的价值远大于对企业的价值。

微信早已稳坐国内社交工具的头把交椅,基础功能已经很久没什么大革新,更多的努力在营造生态上,通过统一登录、二维码、支付、公众号等等把自己打造为联接一切的入口。

小程序对于微信,不是从0到1的新内容,它本身的能力并没有和之前的内嵌H5有本质的飞越。此时推出小程序平台,是因为微信对自己的生态的过去和未来都有了更清晰的洞见。

不是红利,是清流

2013年8月,微信推出公众号,打开了生态的大门。无数媒体、商家和机构的涌入,将微信从基础的工具建设为繁荣的平台。从市场的结果上来说这是巨大的成功,但从产品的角度上微信并不满意。第一次承担规则的制定者,微信已经足够谨慎,但仍然低估了商家无孔不入的手段。

微信希望商家提供服务,用户用完即走,而商家希望用户订阅,以便日后勾搭。往往一个扫码 + H5的就能搞定的服务,却得通过扫码 + 关注 + 菜单来达成。繁琐的操作影响了用户的即时体验,后续的广告又伤害了长期的用户体验。

2016年1月11微信公开课Pro,张小龙首次公开演讲谈微信4大价值观,很不留情地指出商家过度营销实际伤害了微信,并在最后曝光了正在构思的应用号(即小程序)。小程序通过更强的能力来吸引商家支持,无须下载且无法关注(故意),并进一步限制了推送。

前两天的2017公开课上,张小龙提到小程序的启动日是16年1月9日,这就是说他在项目启动两天后就迫不及待地进行了宣布,可见当时他对小程序的期待。

我大胆揣测一下他的愿景:

  • 小程序搞定所有服务
  • 卡券维持商家与用户的关系
  • 订阅号专心做阅读
  • 服务号老子不要了

所以小程序不是什么操作系统和新红利,它目标是成为服务号与部分订阅号的升级替代,天生就带着限制商家的使命,是一股净化环境的清流。

关键入口:二维码

二维码其实是个古老的发明,早在Windows Mobile时代就出现在智能手机。当时在日本和台湾有一点应用,但在大陆还很鲜见,偶有新潮人士用来印在名片上别人也看不懂。

微信在11年底的3.5版本中就引入了二维码,是国内大厂里启动最早的,扫一扫加好友和登录Web微信都还是很新鲜的体验。12年5月,张小龙已经在朋友圈称二维码将是移动互联网的入口。当时我还没有太在意,如今,看见身边各种商品、广告和公共设施上都印上了二维码,中国成为世界上二维码最便利的国家,不得不佩服他的判断和感谢微信的推广。

张小龙朋友圈

二维码百度指数

从摇一摇到扫一扫,每一次入口的抢占与打通,都是微信的一次超越。小程序这次做的,就是进一步打通微信与服务,而且其关键的入口将仍然是二维码。

通过扫描二维码,我们通常能够到达:

  1. 人(用户/群名片)
  2. 信息、服务的提供者(订阅号、服务号)
  3. 信息、服务(网页)
  4. 其他微信内置功能,如授权、支付

小程序将改进第3点的体验与能力,让其达到与原生功能(第4点)相近的程度。尽管通过网页也能实现大部分的服务,但这种量变的影响很可能带来质变的反应。一旦成功,那微信将成为一切服务的入口

线上入口在哪里

官方的说法是仅提供有限的搜索和消息转发,结合小程序注册要求的命名推荐和唯一性要求,应该可以确定小程序搜索逻辑将和目前公众号的搜索区别不大。微信只提供运行的环境,用户应该由服务商自己去搞定。而且以小程序用完即走的目标,不急着用服务的用户根本不应该被打扰,所以干脆连分享到朋友圈的口子都不开。

我挺喜欢这个逻辑,简单又粗暴,微信从技术的角度也只能做到如此。只是等到1月9号开闸之后,一定有无数的公众号开始发布小程序的推荐和榜单,因为还有二维码这个口子在,朋友圈也难逃轰炸。

当用户使用过小程序之后,会有一个地方存放它们的图标,可以通过它们再次使用。而且这次安卓用户有特别的福利,如果你喜欢一个小程序,可以为它建立桌面图标,像普通应用一样运行。

对于这一点我倒是持保留意见,这增加了不同平台体验的差异,而且对小程序用完即走的精神是个反面的引导。

什么样的小程序是好程序

任何对开发小程序有兴趣的公司或机构都应该先阅读这篇微信小程序平台运营规范,有空的话再去看看张小龙这两届公开课上的演讲。我提炼后的大白话是只要能立即给用户带来价值的服务,关键字是立即和价值。

微信努力把小程序做到小而迅速,就是为了让用户能直达目标,所以应该努力避免让用户在小程序里做选择,而将这个过程前移,让用户看到二维码或链接名称的时候就知道将得到什么,经典的榜样是二维码支付。用户进入小程序后,最好在一两个页面内解决问题(原则上就不允许你超过5个页面),然后赶紧离开(每个页面都强制增加了关闭按钮)。

小程序发布前必须提交微信审核,提审时要求开发者选择一个类目。目前小程序类目的开放非常有限(参考),而且审核非常严格,一旦不符就可能耽误近一周的审核时间(我的亲历)。还有,小程序最多圈定5个类目,这个范围每个月才允许修改一次。最近看到一些同学开发了不少社区类的小程序,我没有找到对应的类目,不知道到时候上不了线是怎样一种心情。

从诸多的限制上看,微信对于小程序的开发秉持了异常谨慎的态度。小程序的类目未来一定会逐渐开放,但现在不欢迎的东西以后也不会欢迎,很多厂商现在就可以死心了。

适合小程序的业务场景

首先繁荣的是将会是线下,一切你需要信息、服务、联接的场景的都可能有小程序需求,无脑列举一批

  • 生活、交通、旅游、餐饮类信息与服务获取(当你需要的时候,身边可能就有二维码)
  • 医务、政务、商务的指引和办理(以前微信内的城市服务,很可能会被导出)
  • 企业自己的办公小程序,家庭自己的内务小程序
  • 智能硬件的控制类小程序,甚至任何商品上可能有服务类小程序(没准这才是物联网的第一阶段)

线上入口更多会集中资讯、电商、工具类,我个人特别期待在教育类方向会出现一些新创新。

小程序的未来

距离小程序发布还有10来天,目前舆论的声音都是欣喜多于担忧,跌了好久的腾讯股票也在公开课后抬头。但就如我之前的结论:短期内小程序对于微信的价值大于企业,它的设计目标偏重用户单向索取服务,对于的收费服务这是利好,对于占大头的免费服务,却看得见用户摸不着钱包。如何满足这类企业的胃口,是微信下一个课题。

根据后续的反馈,小程序未来肯定会开放更多的类目,也有可能向个人开发者开放。我最期待的是增加盈利的途径,如广点通、捐赠,喂饱了开发者的平台才是好平台。

使用IDEA单步调试LeanCloud云引擎服务(Java)

发表于 2016-12-16 | 更新于 2018-05-24 | 分类于 技术

最近在使用LeanCloud的云引擎服务,我使用了Java版SDK,在IDEA中进行项目开发(实际上写的是Kotlin语言)。LeanCloud云引擎提供了一个lean.exe的命令行工具,使用lean up命令可以启动一个http服务,非常方便本地测试。代码修改后使用IDEA重新编译一下即可热更新,不用重新执行命令。

如果业务复杂一些,可能需要加点日志来调查。但如果想跟进一步直接用IDEA单步调试,找遍了它们文档和社区都没有方法,也没有其他的网友分享过,所以今天研究了一下。

因为LeanCloud的Java版运行的是一个Jetty服务,我先尝试不用lean命令行,自己在IDEA中配置了Jetty来运行。结果是能显示Web页,但真正想要调试的API接口都返回404。

研究了一下lean.exe的工作方式,发现它执行lean up后,该进程自己启动了3001端口,提供了一个快速调用API的web页。真正的云业务页面和API服务是它调用mvn jetty:run来运行的,默认是3000端口。而maven是用的开发者自己配置的路径,实际上执行的mvn.cmd jetty:run启用了一串如下java命令:

1
"D:\Program Files\Java\jdk1.8.0_92\bin\java.exe" -classpath "d:\work\maven\bin\..\boot\plexus-classworlds-2.5.2.jar" "-Dclassworlds.conf=d:\work\maven\bin\..\bin\m2.conf" "-Dmaven.home=d:\work\maven\bin\.." "-Dmaven.multiModuleProjectDirectory=D:\svnwork\playground\loanassistant-cloud" org.codehaus.plexus.classworlds.launcher.Launcher jetty:run

分析到这里就有办法了:java是可以通过参数开启远程调试的,只要把java的调试参数配置在mvn.cmd中,应该就可以调试真正的业务接口了。

打开mvn.cmd文件,其中这行是真正的执行语句

1
%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %CLASSWORLDS_JAR% "-Dclassworlds.conf=%M2_HOME%\bin\m2.conf" "-Dmaven.home=%M2_HOME%" "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %CLASSWORLDS_LAUNCHER% %MAVEN_CMD_LINE_ARGS%

在其上增加一条java调试参数-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005然后加入命令行中

1
2
3
set EXT_OPTS="-agentlib:jdwp=transport=dt_socket,server=y,suspend=n,address=5005"

%MAVEN_JAVA_EXE% %JVM_CONFIG_MAVEN_PROPS% %MAVEN_OPTS% %MAVEN_DEBUG_OPTS% -classpath %CLASSWORLDS_JAR% "-Dclassworlds.conf=%M2_HOME%\bin\m2.conf" "-Dmaven.home=%M2_HOME%" "-Dmaven.multiModuleProjectDirectory=%MAVEN_PROJECTBASEDIR%" %EXT_OPTS% %CLASSWORLDS_LAUNCHER% %MAVEN_CMD_LINE_ARGS%

大功告成

这时候运行lean up发现多了一行提示,表示已经打开了5005端口用于调试java

接下来在IDEA中增加Run Remote的配置,其默认的参数即是5005端口

运行刚才的配置

在想要调试的函数中加个断点,通过http://localhost:3001页面测试调用

断点成功,舒服了!

使用Kotlin语言写LeanCloud云后台服务

发表于 2016-12-15 | 更新于 2018-05-24 | 分类于 技术

最近在玩微信小程序,有一部分业务需要部署后端,为了省事我选择了LeanCloud。它有多种语言支持,文档也很完善,能快速搭建服务,正好合适。其后端云引擎支持Node.js、Python、Java、Php四种语言,因为我近来写Android多一些,所以采用了更熟悉的Java。

下载了SDK来一看,是基于maven构建,用法挺简单。但我的云服务需要用到的一个算法是我以前在Android上用Kotlin写的,为了避免重新翻译,我尝试将Kotlin也引入云引擎项目,果然可行。在这记录分享一下。

整个修改分为三步

1. pom配置

增加kotlin的依赖与maven-plugin的配置

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
...
<dependencies>
...
<dependency>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-stdlib</artifactId>
<version>1.0.5</version>
</dependency>
...
</dependencies>

<build>
<plugins>
...
<plugin>
<groupId>org.jetbrains.kotlin</groupId>
<artifactId>kotlin-maven-plugin</artifactId>
<version>1.0.5</version>
<executions>
<execution>
<id>compile</id>
<goals> <goal>compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/main/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
<execution>
<id>test-compile</id>
<goals> <goal>test-compile</goal> </goals>
<configuration>
<sourceDirs>
<sourceDir>${project.basedir}/src/test/kotlin</sourceDir>
</sourceDirs>
</configuration>
</execution>
</executions>
</plugin>
...
</plugins>
</build>
</project>

所以工程的文件结构是这样的

2. 翻译AppInitListener类为Kotlin语言版

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
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
package com.cpiz.loanassistant.cloud

import cn.LeanCloud.LeanEngine
import com.avos.avoscloud.AVOSCloud
import com.avos.avoscloud.internal.impl.JavaRequestSignImplementation
import org.apache.logging.log4j.LogManager
import javax.servlet.ServletContextEvent
import javax.servlet.ServletContextListener
import javax.servlet.annotation.WebListener

@WebListener
class AppInitListener : ServletContextListener {

private val appId = System.getenv("LeanCloud_APP_ID")
private val appKey = System.getenv("LeanCloud_APP_KEY")
private val appMasterKey = System.getenv("LeanCloud_APP_MASTER_KEY")

override fun contextDestroyed(arg0: ServletContextEvent) {
}

override fun contextInitialized(arg0: ServletContextEvent) {
logger.info("LeanEngine app init.")
logger.info("Environment: ${System.getenv("LeanCloud_APP_ENV")}")

// 初始化AVOSCloud,请保证在整个项目中间只初始化一次
LeanEngine.initialize(appId, appKey, appMasterKey)

// 在请求签名中使用masterKey以激活云代码的最高权限
JavaRequestSignImplementation.instance().setUseMasterKey(true)

// 向云引擎注册云函数
// com.cpiz.loanassistant.cloud.CloudKt即为云函数的实现
LeanEngine.register(Class.forName("com.cpiz.loanassistant.cloud.CloudKt"))

if (System.getenv("LeanCloud_APP_ENV") == "development") {
// 打开 debug 日志
AVOSCloud.setDebugLogEnabled(true)

// 如果是开发环境,则设置 AVCloud.callFunction 和 AVCloud.rpcFunction 调用本地云函数实现
// 如果需要本地开发时调用云端云函数实现,则注释掉下面语句。
LeanEngine.setLocalEngineCallEnabled(true)
}
}

companion object {
private val logger = LogManager.getLogger(AppInitListener::class.java)
}
}

3. 开始使用Kotlin写云函数

1
2
3
4
5
6
7
8
9
10
11
12
13
package com.cpiz.loanassistant.cloud

import cn.LeanCloud.EngineFunction
import cn.LeanCloud.EngineFunctionParam
import ......

/**
* 测试云函数
*/
@EngineFunction
fun hello(): String {
return "Hello world!"
}

至此结束,原本的目的只是想让算法那部分直接用Kotlin的实现,但最终做到了使用Kotlin编写整个项目,开发效率可比Java高多了。

博客迁移至Farbox平台

发表于 2016-12-15 | 更新于 2018-05-24 | 分类于 建站

最近几年,空闲的时间越来越少,已经很少再写博客,只是偶然会翻起。从2005至2016,12年一晃而过,因为有博客,那些记忆和心情还冻结在那里,仿佛是昨天。

玩了十二年博客,它曾经属于微软(MsnSpace)、Google(Blogger),然后是自己搭的PJBlog、Wordpress,我从一个充满好奇跃跃欲试的青年,终于变成了一个仍然好奇但再无法在时间上奢侈的中年。我不想再要什么模板、动态、图片,能安安静静想点东西,趁它们没那么快健忘,来得及记录就好。所以越来越喜欢Markdown,可以让人先把东西写下来,再去管格式。

最近突然想重新开始记录,不愿意再面对WP那个愚蠢的编辑器,又舍不得以前那么多老文章,发现Farbox迁移成本最低。虽然丢失了评论,一些文章的图片和下载有问题,但没关系,最宝贵的是文字。

Farbox肯定也不是折腾的终点,我大胆的预测一下:未来的互联网,不管用户使用了哪公司的服务,用户创造的内容是会永远跟随他自己的。

菜鸟追车记,3个月尊瑞驾驶感受

发表于 2014-01-29 | 更新于 2018-05-25 | 分类于 生活

这是我投在汽车之家的作业贴,应该算是13年唯一比较正式的一篇东西,贴到博客上来保存记录

立念

按家乡风俗,男人通常在逢九那年过大生日,我生于八四零九,日前已三十而立。在生日的前一个月,我收获了人生的第一部车——凯美瑞尊瑞2.5HG。这是份宝贵的大礼,抢在了下一代还没落地之前,给生活注入了新的激情和色彩。

身为一个理工宅,在28岁之前对汽车没一点追求,这让一毕业就拿了驾照的老婆觉得很奇怪,笑我“兴(趣)取向”不正常。我在回忆里搜索了一下,这大概和我儿时强烈的晕车毛病有关,也受到了身边因车祸而改变了人生的两个亲友的影响,玩赛车游戏我可以热血沸腾,拥有一辆的想法却被束之高阁,总觉着很遥远。

明日复明日,毕业了、结婚了、买房了,房子和我公司的路程才十五分钟,而我和我老婆的公司才相距不到百米,在别人挤公交挤地铁各自发誓一定要买车不再受气的时候,我俩天天牵手上下班,再远点的距离就租个免费自行车好不悠哉。

可在大城市,人不可能在一家公司干一生,公司也不可能在一栋楼租到永远,度过了两年我认为人生最自在的时光后,空间的问题终于开始困扰我们。

我换了更好的单位,依旧十五分钟路程,但必须得两轮。朝暮骑行身影虽矫健,也难免风雨里狼狈。坐公交?可惜走三趟转两道反而时间数倍。

老婆单位也将要换更好的大楼,依旧十五分钟路程,还得四轮才行……趁没搬离,有时我下班绕来载她,自以为甜蜜蜜,直到一天大概是将她颠坏,说“我不想三十岁了还坐自行车后座”,将我一厢情愿打碎。

好好想了想,是该买个车了,方便接送老婆,以后还会有孩子,父母来广州玩也不用再带他们转公交钻地铁。对自己而言,车是腿的延伸,从此广州不是只有天河体育中心一个商圈,一天内广佛东深随便来回,一个周末便能享受广东大部分的景点。

学车

等产生买车的念头,早已过了最佳学车的时机。如果当年读大学时花愿意两千块和一个星期,如果刚来广州时愿意花四千块和三个月,怎会沦到当下要花六千块加近一年的繁琐。

去年10月,通过朋友的推荐,找到一位好教练,愿意认真地教授车内车外各种知识。只是因为工作紧张,只有周末有空闲,平时都到凌晨两点多才睡,周六早晨7点半起床实在苦不堪言,迷迷糊糊的脑子用一杯咖啡浇醒,车子怎么起步都得回忆半天。

幸好手脑还算灵光,理工男品质也发挥出来,很快喜欢上操控这种四轮机械的感觉,开始希望能拥有一台自己的车。只是学车靠自己,排考靠大家,每训练好一个环节,后面都是一两个月的等待,只能心里干灼急……

摇号,选车

广州从去年7月份开始限购,从路人到车主的路上,拦在面前的除了驾照,还有指标书一张。报名学车的同时,我用老婆的驾照申请了摇号,估摸着按当时1/16的概率,只要运气不是太差,等我拿到驾照之后,指标也应该到手了。

老天开了一个善意的玩笑,只用了3个月我们就获得了指标,13年8月26号之前必须购车。这结果让我们哭笑不得,太早买的话用不着(后来证明这想法是太Simple了),放弃的话老婆两年内不能再参加摇号,等我自己的驾照出来再摇不知得等到猴年马月了。

好,那就开始选车。

最初想主要用于日常代步,节假出游,又是新手,买个十五六万的A级车差不多了,过几年再换更好的。向身边有车的朋友征求建议,结果几乎所有人都推荐一步到位上B级车。其中有一个理由动摇了我:反正早晚是要升级,就是差个几万块钱,但一年后宽裕了再想换车到时候肯定舍不得,开几年再换又心理不甘,而且当时还有换车后排量能降不能升的担忧。最后老婆鼓励了一下:”买个好点的吧,30w以内都可以,当作给你30岁的生日礼物“,遂美滋滋更换目标。

当时我对汽车的了解仅限于认识车标,这才开始泡汽车之家、新车评,恶补知识。在学车的同时,也开始了漫长反复的看车之路。

我们初定的筛选的标准:

落地30W以内,尽量别太贵

只在城市活动,相比SUV,更倾向轿车

不考虑韩国品牌,缺乏信心

不考虑国产品牌,缺乏信心

尽量非日本品牌,我不仇日,但怕仇日的愤怒青年
以上无论如何,车必须有亮点,可以是最帅、最精致、性能最好、最经济、最有科技感……总之拒绝平庸。

实际证明,选车过程很难做到完全理性,也没有完美的车,最后的结果往往偏离预期很大。这其中,就留给了汽车软文、广告、销售人员很大的影响空间。

最开始,我看中了朋友推荐的新蒙迪欧。当时只有图片可看,一眼就被它潇洒的线条所吸引,还有那犀利的大灯,憨憨的大嘴。接着看了新车评关于老蒙的视频与文章,知道机械性能也很强大,符合理工宅要求。决定将看车的处女行献给福特,先看看老蒙情况,也打听打听新蒙消息。找了一个周末下午来到黄埔大道东的翰福,可能我们穿着太屌丝(我平常都是T恤短裤拖鞋、老婆每天双肩包牛仔裤),完全没工作人员来搭理。转了一圈展厅没见老蒙,只好主动咨询销售,感觉不是很热情,在我表露出对新蒙有意后也没想着主动建立联系,而且一问三不知。好,那等有新消息再来。

相信朋友们都有经历,伴随买车的念头从无到有,人走在路上,也有一个从对汽车毫不在意到念念不忘的变化。以前那些看起来都差不多的铁壳盖轮子,一下变成了缤纷的奥迪、丰田、现代、小型车、中型车、SUV……,人也会开始去记忆车的品牌和型号。某天骑行路上,看见个好漂亮的SUV屁股,只记住了本田和一个单词Cross。后来查到它叫歌诗图(Crosstour),也不是SUV,是介于SUV和轿车的旅行车。找个周末拉上老婆逛本田4S,不等我指引,她也瞬间被这车所吸引,我也是第一次近距离感受它。这车前脸大气、后尾性感、拉丝内饰精致、座舱和后尾空间都超赞,完全给人一个豪华车的感觉,竟然只卖26w。原来对日本车的那份担心,在如此的触手可及面前立即变得薄如轻烟,而且瞬间找好了理由:广州是日本车的大本营(广丰、广本),而且广州素来开放,没那么容易有事的……(节操啊)

新蒙有了对手,我的心思也活了起来:既然不再介意日本车,那再考虑考虑尊瑞?尊瑞首次印象是去年年底在电梯里看到的广告,而且内容还全都记得,百分百中签、厂家优惠3w、政府还补贴1w,省油环保而且还堪比3.0发动机的动力,这车有这么神?一了解真吃了一惊,这是新车评网史上评价最高的长测车,丰田的混合动力技术已经经过国外市场检验可以不用担心,电池也给8年20w公里保修,而且广州有全国最高的3.6w优惠加1w政府补贴,太有诱惑力了。瞬间我又找到了放弃歌诗图的理由:太长太宽不适合我新手,而且车重油耗高……(节操)

中间还关注了一阵迈腾,为它的精致内饰和空间所倾倒,不过315曝光DSG问题后大众大事化小小事化了的表现让我觉得很不放心,不敢考虑。

购车

五月份时候,在另一家福特4S得到新蒙七月份即将上市的消息,出于对老蒙的信心和新车配额与指标期限的担忧,在没见过样车甚至不知道定价的情况下,我预定了新蒙200P豪华版(协议要求必须保证七月份提车否则全额退订金),开始天天在之家新蒙版块守望。不知是因为水军多还是脑残太多,新蒙论坛每天乌烟瘴气,各种口水谩骂,偶尔出几个理性分析的帖子也被黑成车托,最后导致了回帖必须附上一段“车托全家火葬场”的诅咒才能证明自身清白。偶尔到凯美瑞版块潜水倒是一片和谐,搜索关键字“故障”找到的结果也不算多,尊瑞更是一片赞声。考虑到新蒙跳票的风险,将尊瑞作为备胎倒是一个不错的选择,起码它是广州生产、货源充足,订车不用等太久而导致指标过期。

期间又反复读了新车评的尊瑞长测,也更多的了解了能量回收、动力策略还有ECVT变速箱的工作原理,越发觉得精妙,在真正的新能源技术还遥遥无期的情况下,丰田这套混动的机理简直就是唯一正确的设计!抽空去丰田4S看了展车,虽然感觉外观实在没个性,但对它的内饰和空间都非常满意,很喜欢那仿碳纤维面板的材质颜色(相比普凯的桃木风格则完全不能接受)。销售蔡M的表现非常专业,很干脆地解答了我们所有疑惑,包括优惠、能否享受政府补贴、提车时间、贷款方案,回家后我们正式确定将尊瑞HG列为第一备胎。

不知是不幸还是有幸,新蒙上市的时间果然越推越迟,销售终于打电话通知我正式提车时间为八月底,我是第一批,但这个结果已毫无意义。

新蒙无缘,只好买尊瑞了!7月6号,再次来到丰田第一店,参照网友们的购车价格,很快谈到尊瑞HG珍珠白加装4S的那套科技版套装(包括导航、CMMB电视、液晶头枕、日行灯、座椅通风、中置喇叭、后视镜自动翻转折叠)、人保保险、送贴膜抱枕地毯方向盘锁,最终含政府补贴落地价25.4w(后来还是发现亏了先不表),销售承诺一个月内到车。

以上,终于完成了我的选车之路,而整个过程,我因为一直没拿到驾照,只能试乘,未能试驾过任何一辆。

提车

7月31号终于等来了电话,通知我8月2号可以提车,而这一天,正好是我驾考最后一个科目以及发证的时间,这不得不说是一个奇妙的巧合。就这样,我上午去车管所考安全文明、宣誓、领证,随后打车到4S见我爱车第一面。

一店的车库原来是在麦德龙停车场的最顶层,停满了新车,我那辆就静静地趴在那,那么普通,那么特别。蔡M给了钥匙让我验车,我一驾照还没揣热的人又紧张又懵懂,只知道一定不能松驻刹不能乱挂档,手忙脚乱搞一通加上车子暴晒一上午炎热无比很快就满身大汗的出来了。

回到店里交好尾款,理论上这车已经完全归我,可以当天开走。考虑到对新车不熟悉,办牌手续和加装配置没有完成,还是留在了店里。

8月12号,应4S安排跟一批丰田新车主到水荫路车管所集体办牌,尝试N次后选了一个对自己有意义的牌号。

8月14号,4S来电通知自选的配置已加装完毕,终于可以正式提车!约了朋友翘班来帮忙,刚好赶上台风,匆匆到店后销售给给了一叠文件讲了一堆东西也没太听进去,没有很激动,只是感觉不太真实,就这样我就车主了?

车开回家后我两天没敢动,等到周末才把朋友再约出来带我练练。好在驾校还是学了点东西,很快就顺手了。

用车感受

不知不觉尊瑞已经开了三个多月,期间上下班通勤、周末出游、国庆来回一趟江西老家,目前里程将近5000公里,刚做完了首保。这篇作业也拖拖拉拉写了两个多月,因为各种原因和借口一直没有提交。这里再结合我一个菜鸟司机的成长历程,写一点尊瑞感受:

最深刻的感受是安逸,这一点不得不夸。

坛子里有朋友发过各种算法:一年要开多少公里,多少年后能把尊瑞相比普凯的溢价赚回来。买车前我也结合自己的情况计算过,但开过一段时间后,发现这个念头完全可以抛开。混合动力是比普凯省油,但这个省油不是冷冰冰的数字,而是相比其他2.5L的汽油车主来说完全不一样的轻松心情。

咱这个收入级别的人,身边朋友也大都开30w以内的车,油耗免不了是日常的话题之一,君不见每次油价调整都会激起Q群里大片的讨论。相比起其他车友的敏感,尊瑞车主确实淡定很多。就算不谈油价,每个月少去一次加油站排队也省心不少。

尊瑞的仪表设计其实很有心机,取消了发动机转速表,却有中控动力示意图、行车电脑小屏、右侧的油耗表、左测的动力表至少4个地方全方位暗示你我在省油我很省油,到达目的地后还发一朵“燃油经济性优”的小红花鼓励,就差学360再提示一个“你的油耗打败了全国XX%车主”。在这种暗示下,新车主都会经过一个改善驾驶习惯挑战极限油耗的“自我培训”过程,一段时间后新鲜劲过了可能不再理会,但这时候已经建立起了对尊瑞省油能力的信任,同时养成了对油耗完全不在乎的心态。这种心态带给我的是想去哪就去哪的自由,没事也愿意去阅江路兜个风散散步,走错路也毫无负担。

省油还好说,而尊瑞纯电动行驶时的安静却是不好形容。汽车发明了一百多年,我们对它的印象就是应该嗡嗡作响,性能跑车们甚至以此为荣,突然遇到一辆光滑行不出声的车,这种感觉是很新鲜的,每一个初次试驾我车的朋友都会疑问:”这真的启动了?“,当我习惯了这种设定之后,很快感受到它带来的好处。

路上堵车、等红灯,车窗外其他的车嗡嗡颤抖,尊瑞却悄悄熄了火,安逸。前车一动则悄然起步,从容。

小区路窄,行人背后尊瑞静静跟随,也许是自我陶醉,总觉得路人惊觉后瞥来的目光里带着温暖。没它之前,我也做了近30年路人,也希望多遇到点这样的车治愈一下惊吓过的心灵。

驾驶尊瑞,我愿意做个好司机,我文明礼让,你低碳环保。

无图无真相

尊瑞的外观从开始就感觉平平无奇,买来后看得多了变得稍微顺眼,但仍不算一辆漂亮的车,提不起拍照的欲望。只是偶尔它讨好心情时,用手机记录一张。就喜欢它静静地趴在那里,随时带我去想去的地方。

到手的第二个周末,它带我去南沙吃海鲜,从此游玩终于不再受限。

小区车位紧张,一直停在外面,这是第一次带它回家时拍的。

第一次从这个角度看广州的桥

国庆的时候,起个大早,它带我奔行800公里回老家,再也不为买票愁

一把$100的刷子——Clarisonic Mia拆解与修复

发表于 2013-01-20 | 更新于 2018-05-24 | 分类于 项目

家里有把叫Clarisonic Mia的刷子,是LP大人花100刀从美帝淘回来的宝贝。这宝贝的毛刷据说能以声波的频率振动,清毛孔去黑头什么什么的就跟橡皮擦一样,手感扎实线条性感全身防水,还是时髦的无线充电技术,LP大人每天刷脸爱不释手。

好景不长,用了三个月,昨天充电时开始出现约每秒一次的振动,指示灯也不闪,十几个小时之后毫无效果。一搜发现这问题还比较普遍,有的运气好充一会儿就恢复了,有的就此Over。海淘有海淘的风险,Clarisonic不支持全球联保,来回美国一趟又得花去300大洋。

看着LP大人一脸的不开心,也为了钱包考虑,我尝试着拆解修复一下。可惜找遍国内国外,没有发现任何关于拆解的介绍(果然是女人用的东西),只能硬着头皮上。

过程记录如下,希望对苦逼的男同胞们有帮助。事后补录,中间忘了拍照。

——————– 我是撬不开的分割线 ———————

Clarisonic Mia全身没一个螺钉,从边缝撬了半天纹丝不动,干脆打了个孔。结果发现外壳厚度至少有4mm,前后盖之间是极其完美的粘接。遂改方法为热切割:将美工刀片用燃气烧热,垂直切割边缝一周。完成后仍然无法分离,强行撬开后发现内部还用了多处白色的胶体来粘结。

所有元件均附着在前盖,头部是两片交叉成X形的簧片,上两端固定,下两端是铁件并连接一根曲柄输出。中部是一个W形的电磁铁,顶部两极与X簧片的铁件隔空对应。刷子的工作原理应该是快速变换电磁铁的两级来驱动簧片左右摆动,最后输出至曲柄连接的刷头。下部是两节串联的白色平头电池,型号为NiMh-AA-2-900-PB3(镍氢!怎么不用锂电?),电池极点是钢焊。

拆下电池用万用表测量电压才零点几伏,换上一对南孚后刷子又开始嗡嗡工作(试过外接电源,振动频率异常,推测应该是整流不干净),说明机器本身没问题。折腾了一下这一对小白,重新接入,粘上无线充电器,竟然恢复充电了!看来之前应该就是电池过放造成的无法充入。100刀的东西如果是为了安全使用镍氢电池可以理解,但无线充电都用上了,充放保护怎么这么差?

充电一夜后可以恢复工作,基本判断问题已解决,开始复原。手头上可用的胶水只有热熔枪,先将电池粘牢在电路板,然后用美工刀将前后盖的外缘削出斜面,使两盖合并后接缝呈外宽内窄的沟状,便于胶水深入。再用热熔胶填满一周,最后打磨边缘、削去凸出的胶水。还有之前撕掉了开关处的胶片,重新粘回去。至此——密封应该凑合了吧……最后是这个样子

一些后话:

  1. Clarisonic的外形设计、注塑工艺、表面处理、内部粘焊都是精工细致,无可挑剔
  2. Clarisonic这种一体化的工艺,压根就没考虑过维修问题,保修只能换新
  3. 女人的钱好赚,就算它如此牛逼的工艺和设计卖$100还是太贵了,¥200差不多

2013/06/16 update:

这问题后来又折腾了我两次,其实很好解决,拆开后用个3-5v电源(比如锂电或USB)接触电池对应两极3-5秒进行激活,然后就能正常无线充电了。最后我干脆接了两条引线出来,丑虽丑点,一劳永逸。

12…17

Cpiz

Cpiz's blog

170 日志
10 分类
230 标签
RSS
GitHub E-Mail
© 2019 Cpiz
由 Hexo 强力驱动 v3.7.1
|
主题 — NexT.Mist v6.3.0