上篇文章介紹了xcodebuild的命令使用。
1.連接設備
這裏本篇介紹如果連接手機, 安裝app.
因爲製作工具, 新建了一個mac app項目,導入需要使用的私有API, MobileDevice.framework.
路徑: /System/Library/PrivateFrameworks/MobileDevice.framework
這個文件是沒有頭文件,自己導入一下頭文件MobileDevice.h , 可以自己晚上找找,傳送門
這裏主要記錄一下常用的幾個接口, 註釋也是比較詳細。
mach_error_t AMDeviceNotificationSubscribe(am_device_notification_callback
callback, unsigned int unused0, unsigned int unused1, void* //unsigned int
dn_unknown3, struct am_device_notification **notification);
在當前線程註冊一個函數, 有設備連接時, 會進行通知,
struct am_device_notification *notify;
AMDeviceNotificationSubscribe(&device_callback, 0, 0, NULL, ¬ify);
回調方法:
void device_callback(struct am_device_notification_callback_info *info, void *arg) {
switch (info->msg) {
case ADNCI_MSG_CONNECTED:
{
//device connect info->dev
break;
}
case ADNCI_MSG_DISCONNECTED:{
//device disconnect
break;
}
default:
break;
}
}
設備連接和設備斷開, info->dev獲取設備的信息。 調用
CFStringRef AMDeviceCopyValue(struct am_device *device, uint32_t, CFStringRef cfstring);
獲取設備信息, 參數分別爲, 設備, 0, 關鍵字。
關鍵字在頭文件裏面有詳細記錄,
例如獲取設備名稱, 在獲取之前必須連接設備, 要不無法獲取。網上的很多資料都沒有查到, 坑了我不少時間。
AMDeviceConnect(dev); //nessesary
AMDeviceCopyValue(dev, 0, CFSTR("DeviceName"));
AMDeviceDisconnect(dev); //nessesary
2.安裝
void handle_device(AMDeviceRef device) {
if (found_device) return; // handle one device only
CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier(device);
if (device_id != NULL) {
if(strcmp(device_id, CFStringGetCStringPtr(found_device_id, CFStringGetSystemEncoding())) == 0) {
found_device = true;
} else {
return;
}
} else {
found_device = true;
}
CFRetain(device); // don't know if this is necessary?
printf("[ 0%%] Found device (%s), beginning install\n", CFStringGetCStringPtr(found_device_id, CFStringGetSystemEncoding()));
AMDeviceConnect(device);
assert(AMDeviceIsPaired(device));
assert(AMDeviceValidatePairing(device) == 0);
assert(AMDeviceStartSession(device) == 0);
CFStringRef path = CFStringCreateWithCString(NULL, app_path, kCFStringEncodingASCII);
CFURLRef relative_url = CFURLCreateWithFileSystemPath(NULL, path, kCFURLPOSIXPathStyle, false);
CFURLRef url = CFURLCopyAbsoluteURL(relative_url);
CFRelease(relative_url);
int afcFd;
assert(AMDeviceStartService(device, CFSTR("com.apple.afc"), &afcFd, NULL) == 0);
assert(AMDeviceStopSession(device) == 0);
assert(AMDeviceDisconnect(device) == 0);
assert(AMDeviceTransferApplication(afcFd, path, NULL, transfer_callback, NULL) == 0); //安裝操作回調函數
close(afcFd);
CFStringRef keys[] = { CFSTR("PackageType") };
CFStringRef values[] = { CFSTR("Developer") };
CFDictionaryRef options = CFDictionaryCreate(NULL, (const void **)&keys, (const void **)&values, 1, &kCFTypeDictionaryKeyCallBacks, &kCFTypeDictionaryValueCallBacks);
AMDeviceConnect(device);
assert(AMDeviceIsPaired(device));
assert(AMDeviceValidatePairing(device) == 0);
assert(AMDeviceStartSession(device) == 0);
int installFd;
assert(AMDeviceStartService(device, CFSTR("com.apple.mobile.installation_proxy"), &installFd, NULL) == 0);
assert(AMDeviceStopSession(device) == 0);
assert(AMDeviceDisconnect(device) == 0);
mach_error_t result = AMDeviceInstallApplication(installFd, path, options, install_callback, NULL);
if (result != 0)
{
printf("AMDeviceInstallApplication failed: %d\n", result);
exit(1);
}
close(installFd);
CFRelease(path);
CFRelease(options);
printf("[100%%] Installed package %s\n", app_path);
if (!debug) exit(0); // no debug phase
AMDeviceConnect(device);
assert(AMDeviceIsPaired(device));
assert(AMDeviceValidatePairing(device) == 0);
assert(AMDeviceStartSession(device) == 0);
printf("------ Debug phase ------\n");
mount_developer_image(device); // put debugserver on the device
start_remote_debug_server(device); // start debugserver
write_gdb_prep_cmds(device, url); // dump the necessary gdb commands into a file
CFRelease(url);
printf("[100%%] Connecting to remote debug server\n");
printf("-------------------------\n");
signal(SIGHUP, gdb_ready_handler);
pid_t parent = getpid();
int pid = fork();
if (pid == 0) {
system(GDB_SHELL); // launch gdb
kill(parent, SIGHUP); // "No. I am your father."
_exit(0);
}
}
//回調函數, 當前操作的狀態,
void transfer_callback(CFDictionaryRef dict, int arg) {
int percent;
CFStringRef status = CFDictionaryGetValue(dict, CFSTR("Status"));
CFNumberGetValue(CFDictionaryGetValue(dict, CFSTR("PercentComplete")), kCFNumberSInt32Type, &percent);
if (CFEqual(status, CFSTR("CopyingFile"))) {
CFStringRef path = CFDictionaryGetValue(dict, CFSTR("Path"));
if ((last_path == NULL || !CFEqual(path, last_path)) && !CFStringHasSuffix(path, CFSTR(".ipa"))) {
printf("[%3d%%] Copying %s to device\n", percent / 2, CFStringGetCStringPtr(path, kCFStringEncodingMacRoman));
}
if (last_path != NULL) {
CFRelease(last_path);
}
last_path = CFStringCreateCopy(NULL, path);
if (last_path != NULL) {
CFRelease(last_path);
}
}
CFRelease(dict);
CFRelease(status);
}
void install_callback(CFDictionaryRef dict, int arg) {
int percent;
CFStringRef status = CFDictionaryGetValue(dict, CFSTR("Status"));
CFNumberGetValue(CFDictionaryGetValue(dict, CFSTR("PercentComplete")), kCFNumberSInt32Type, &percent);
printf("[%3d%%] %s\n", (percent / 2) + 50, CFStringGetCStringPtr(status, kCFStringEncodingMacRoman));
CFRelease(dict);
}
2個關鍵點,設備和安裝的app。