构建iOS 远程调试环境

预备环境:
macOS jailbreak iOS

1 拷贝debugserver 至Mac 本地

1
2
scp root@{iOS ip}:/Developer/usr/bin/debugserver ~/debugserver
lipo -thin arm64 ~/debugserver -output ~/debugserver

2 给debugserver 添加 task_for_pid 权限
新建文件 ent.xml

1
2
3
4
5
6
7
8
9
10
11
12
<plist version="1.0">
<dict>
<key>com.apple.springboard.debugapplications</key>
<true/>
<key>get-task-allow</key>
<true/>
<key>task_for_pid-allow</key>
<true/>
<key>run-unsigned-code</key>
<true/>
</dict>
</plist>

1
ldid -Sent.xml debugserver

3 将处理过后的 debugserver 拷贝会 iOS

1
2
3
scp ~/debugserver root@{iOS ip}:/usr/bin/debugserver
ssh root@{iOS IP}
chmod +x /usr/bin/debugserver

常看 库支持的架构 lipo -info {bin}

使用 debugserver

相关知识:
ssh
scp
lipo
ldid

reference

The Compiler is Mine Friend

Apple LLVM compiler

Warning Flag 语法

  • -Wfoo 开启 foo,foo表示一类或者一组警告
  • -Wno-foo 关闭 foo 警告
  • -w 关闭所有的警告

设置 Warning = Errors

//.xccongig
GCC_TREAT_WARNINGS_AS_ERRORS = YES
// cms-ling
-Werror

编译器给出的几类警告:

  • A valid issue => Fix the issue
  • 你不关心的,或者无意义的警告 => 关闭 局部或者全局 警告
  • 你不理解的警告 => 弄明白,否者你永远不明白

常见的警告组合

-Wall
-Wextra
-Wpedantic
-Weverything
-Wshadow

1
2
3
4
5
6
int main(int argc, char *argv[]) {
if ( 1 == 1 ) {
int argc = 9;
printf("integere is %d", argc);
}
}

-Wfloat-equal 浮点数相等比较

1
2
3
4
5
float a = 2.0
flaot b = 3.1
if (a == b) {
// TODO
}

-Wundef #if 中使用了未定义的符号

1
#if THIS_HAS_NOT_BEEN_DEFINED

-Wempty-body if else do while 不会执行的代码段

1
2
3
4
5
if (1 == 2) {
// TODO
} else {
// When invoke?
}

-Wnewline-eof 文件的结尾符不是空行

Clang 中新的 警告 类型
-Wobjc-literal-compare
-Warc-repeated-use-of-weak

关闭 警告

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#pragma clang diagnostic push
#pragma clang diagnostic ignore "-Wstupid-method-name"
- (BOOL)doTheThingWithTheOtherThing {
// TODO
}
#pragma clang diagnostic pop
- (void)doThingWithObject(NSObject * __attribute__((unused)))thingie {
// TODO
}
- (void)doThingWithObject(NSObject * __unused)thingie {
// TODO
}
- (void)doThingWithObject(NSObject *)thingie {
#pragma unused(thingie)
// TODO
}

add Complier Flags -W

Function Attribute attribute ((attribute-list))

reference

VersionControl

SVN

reference

http://svnbook.red-bean.com/
https://subversion.apache.org/
https://tortoisesvn.net/

Git

TFS

Mercurial

###reference

Crash

解析Crash准备的材料

  • 原材料:Crash log
  • 辅料: dysm 和 app
  • 工具: symbolicatecrash, otool, xcrun, atos

收集材料

  • (Xcode)Windows -> Device -> View Device Logs
  • Log 收集第三方平台
  • 打包应用时的 .xcarchive(dysm, app)

第一道菜 Symbolicatecrash

1
2
3
find /Applications/Xcode.app -name symbolicatecrash -type f
/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash

分析

1
2
3
4
5
6
7
8
9
10
11
12
/Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash 56ae4a1e0feaad87628b4c8e.crash ThumbDoctor.app.dSYM > crash.txt
---
## Warning: Unable to symbolicate from required binary: /Users/lkeg/Library/Developer/Xcode/iOS DeviceSupport/8.3 (12F70)/Symbols/System/Library/Frameworks/CoreLocation.framework/CoreLocation
---
出现
----
Error: "DEVELOPER_DIR" is not defined at /Applications/Xcode.app/Contents/SharedFrameworks/DTDeviceKitBase.framework/Versions/A/Resources/symbolicatecrash line 60.
----
export DEVELOPER_DIR="/Applications/XCode.app/Contents/Developer"

第二道菜 符号地址逐行解析

起始地址:即使每次iOS app启动都会加载(main module)主模块在不同的内存地址(大多数情况下32bit框架对应的地址是0x4000、64bit框架对应的地址为0x0000000100000000)。

  • cd xx.app
  • 1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    otool -arch arm64 -l xxx.app/xxx | grep -B 1 -A 10 "LC_SEGM" | grep -B 3 -A 8 "__TEXT"
    Load command 1
    cmd LC_SEGMENT_64
    cmdsize 952
    segname __TEXT
    vmaddr 0x0000000100000000
    vmsize 0x00000000000b8000
    fileoff 0
    filesize 753664
    maxprot 0x00000005
    initprot 0x00000005
    nsects 11
    flags 0x0

其中 vmaddr 0x0000000100000000 地址便为我们所要的app运行起始地址。

计算 symbol address

symbol address = 地址偏移量+起始地址。
起始地址上面我们已经得到,地址偏移量就是单行信息中“+”号后面的数值。

解析 symbol address

xcrun atos –arch arm64 -o xxx.app/xxx [addresss]

load address 相对偏移解析

xcrun atos –arch arm64 -o xxx.app/xxx -l [address] [address]

reference

Comunication

URL Scheme

完整的:
scheme://user:password@host:port/path?query#fragment
简化的:
scheme://host/path?query

NSURL
NSURLComponents
@interface NSString (NSURLUtilities)

// Returns a new string made from the receiver by replacing all characters not in the allowedCharacters set with percent encoded characters. UTF-8 encoding is used to determine the correct percent encoded characters. Entire URL strings cannot be percent-encoded. This method is intended to percent-encode an URL component or subcomponent string, NOT the entire URL string. Any characters in allowedCharacters outside of the 7-bit ASCII range are ignored.

  • (nullable NSString )stringByAddingPercentEncodingWithAllowedCharacters:(NSCharacterSet )allowedCharacters NS_AVAILABLE(10_9, 7_0);

// Returns a new string made from the receiver by replacing all percent encoded sequences with the matching UTF-8 characters.
@property (nullable, readonly, copy) NSString *stringByRemovingPercentEncoding NS_AVAILABLE(10_9, 7_0);

  • (nullable NSString *)stringByAddingPercentEscapesUsingEncoding:(NSStringEncoding)enc NS_DEPRECATED(10_0, 10_11, 2_0, 9_0, “Use -stringByAddingPercentEncodingWithAllowedCharacters: instead, which always uses the recommended UTF-8 encoding, and which encodes for a specific URL component or subcomponent since each URL component or subcomponent has different rules for what characters are valid.”);
  • (nullable NSString *)stringByReplacingPercentEscapesUsingEncoding:(NSStringEncoding)enc NS_DEPRECATED(10_0, 10_11, 2_0, 9_0, “Use -stringByRemovingPercentEncoding instead, which always uses the recommended UTF-8 encoding.”);

@end

App 之间Comunication
设置
plist
发送

1
2
3
// UIApplication
- (BOOL)openURL:(NSURL*)url NS_EXTENSION_UNAVAILABLE_IOS("");
- (BOOL)canOpenURL:(NSURL *)url NS_AVAILABLE_IOS(3_0)

接受

1
2
3
4
// UIApplicationDelegate
- (BOOL)application:(UIApplication *)application handleOpenURL:(NSURL *)url NS_DEPRECATED_IOS(2_0, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)application openURL:(NSURL *)url sourceApplication:(nullable NSString *)sourceApplication annotation:(id)annotation NS_DEPRECATED_IOS(4_2, 9_0, "Please use application:openURL:options:") __TVOS_PROHIBITED;
- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<NSString*, id> *)options NS_AVAILABLE_IOS(9_0); // no equiv. notification. return NO if the application can't open for some reason

refer

设置

web

1 创建 apple-app-site-association 配置文件(没有后缀),文件内包含App可以处理的JSON格式URLs设置
2 上传 apple-app-site-association 文件至HTTPS服务器
3 App完成处理 universal links 编码

实例
{
“applinks”: {
“apps”: [],
“details”: [
{
“appID”: “9JA89QQLNQ.com.apple.wwdc”,
“paths”: [ “/wwdc/news/“, “/videos/wwdc/2015/“]
},
{
“appID”: “TeamID.BundleID2”,
“paths”: [ “
“ ]
}
]
}
}

App

Add an entitlement that specifies the domains your app supports.
Update your app delegate to respond appropriately when it receives the NSUserActivity object.
NSUserActivityTypeBrowsingWeb

1
2
3
4
5
// Called on the main thread after the NSUserActivity object is available. Use the data you stored in the NSUserActivity object to re-create what the user was doing.
// You can create/fetch any restorable objects associated with the user activity, and pass them to the restorationHandler. They will then have the UIResponder restoreUserActivityState: method
// invoked with the user activity. Invoking the restorationHandler is optional. It may be copied and invoked later, and it will bounce to the main thread to complete its work and call
// restoreUserActivityState on all objects.
- (BOOL)application:(UIApplication *)application continueUserActivity:(NSUserActivity *)userActivity restorationHandler:(void(^)(NSArray * __nullable restorableObjects))restorationHandler NS_AVAILABLE_IOS(8_0);

relation

HandOff
Core Spotlight

refer