Skip to content

feat: support Wi-Fi devices #56

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 23, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions IOSDeviceLib/Constants.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,7 @@ static const unsigned kCFStringEncodingUTF8 = 0x08000100;
static const unsigned kAMDNotFoundError = 0xe8000008;
static const unsigned kAMDAPIInternalError = 0xe8000067;
static const int kUSBInterfaceType = 1;
static const int kWIFIInterfaceType = 2;
static const unsigned kAppleServiceNotStartedErrorCode = 0xE8000063;
static const unsigned kMountImageAlreadyMounted = 0xE8000076; // Note: This error code is actually named kAMDMobileImageMounterImageMountFailed but AppBuilder CLI and other sources think that getting this exit code during a mount is okay
static const unsigned kIncompatibleSignature = 0xE8000033; // Note: This error code is actually named kAMDInvalidDiskImageError but CLI and other sources think that getting this exit code during a mount is okay
Expand All @@ -39,6 +40,7 @@ static const char *kUnreachableStatus = "Unreachable";
static const char *kConnectedStatus = "Connected";

static const char *kDeviceFound = "deviceFound";
static const char *kDeviceUpdated = "deviceUpdated";
static const char *kDeviceLost = "deviceLost";
static const char *kDeviceTrusted = "deviceTrusted";
static const char *kDeviceUnknown = "deviceUnknown";
Expand Down Expand Up @@ -69,6 +71,8 @@ static const char *kResponseCommandType = "responseCommandType";
static const char *kResponsePropertyName = "responsePropertyName";
static const char *kShouldWaitForResponse = "shouldWaitForResponse";
static const char *kCommandType = "commandType";
static const char *kIsWiFiConnected = "isWiFiConnected";
static const char *kIsUSBConnected = "isUSBConnected";
static const char *kTimeout = "timeout";
static const char *kPort = "port";
static const char *kHost = "host";
Expand Down
6 changes: 4 additions & 2 deletions IOSDeviceLib/Declarations.h
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,8 @@ struct DeviceData {
std::map<const char*, ServiceInfo> services;
int sessions;
std::map<std::string, ApplicationCache> apps_cache;
int isWiFiConnected;
int isUSBConnected;

void kill_device_server()
{
Expand Down Expand Up @@ -168,7 +170,7 @@ typedef void(__cdecl *cfdictionary_get_keys_and_values)(CFDictionaryRef, const v
typedef CFStringRef(__cdecl *cfstring_create_with_cstring)(void*, const char*, unsigned);
typedef CFArrayRef(__cdecl *cfarray_create)(void*, const void**, long, void**);
typedef unsigned(__cdecl *device_secure_operation_with_path)(int, const DeviceInfo*, CFURLRef, CFDictionaryRef, void(*f)(), int);
typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(int, const DeviceInfo*, CFStringRef, int, void(*f)(), int);
typedef unsigned(__cdecl *device_secure_operation_with_bundle_id)(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *));
typedef void(__cdecl *cfrelease)(CFStringRef);

typedef CFDictionaryRef(__cdecl *cfdictionary_create)(void *, void*, void*, int, void*, void*);
Expand Down Expand Up @@ -276,8 +278,8 @@ extern "C"
unsigned AMDeviceCreateHouseArrestService(const DeviceInfo*, CFStringRef identifier, void * unknown, AFCConnectionRef * handle);
int AMDeviceGetConnectionID(const DeviceInfo*);
int AMDeviceGetInterfaceType(const DeviceInfo*);
unsigned AMDeviceSecureUninstallApplication(ServiceConnRef connection, const DeviceInfo*, CFStringRef bundleIdentifier, CFDictionaryRef params, void (*installCallback)(CFDictionaryRef*, void *));
unsigned AMDeviceUninstallApplication(HANDLE, CFStringRef, void*, void(*f)(), void*);
unsigned AMDeviceSecureUninstallApplication(int, const DeviceInfo*, CFStringRef, int, void(*f)(), int);
unsigned AMDeviceStartSession(const DeviceInfo*);
unsigned AMDeviceStopSession(const DeviceInfo*);
unsigned AMDeviceConnect(const DeviceInfo*);
Expand Down
76 changes: 58 additions & 18 deletions IOSDeviceLib/IOSDeviceLib.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -134,6 +134,7 @@ int start_session(std::string& device_identifier)
{
const DeviceInfo* device_info = devices[device_identifier].device_info;
UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceConnect(device_info), start_session_mutex);
assert(AMDeviceIsPaired(device_info));
UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceValidatePairing(device_info), start_session_mutex);
UNLOCK_MUTEX_AND_RETURN_IF_FAILED_RESULT(AMDeviceStartSession(device_info), start_session_mutex);
}
Expand Down Expand Up @@ -242,14 +243,26 @@ void get_device_properties(std::string device_identifier, json &result)
result["deviceName"] = get_device_property_value(device_identifier, "DeviceName");
result["productVersion"] = get_device_property_value(device_identifier, kProductVersion);
result["deviceColor"] = get_device_property_value(device_identifier, "DeviceColor");
// available values:
// "BluetoothAddress","BoardId","CPUArchitecture","ChipID","DeviceClass",
// "DeviceColor","DeviceName","FirmwareVersion","HardwareModel",
// "ModelNumber","ProductType","ProductVersion","UniqueDeviceID","WiFiAddress"
}

inline bool has_complete_status(std::map<std::string, boost::any>& dict)
{
return boost::any_cast<std::string>(dict[kStatusKey]) == kComplete;
}

void on_device_found(const DevicePointer* device_ptr, std::string device_identifier, std::string eventString, json &result)

void update_device_result(std::string device_identifier, json &result)
{
result[kIsUSBConnected] = devices[device_identifier].isUSBConnected;
result[kIsWiFiConnected] = devices[device_identifier].isWiFiConnected;
get_device_properties(device_identifier, result);
}

void on_device_found(const DevicePointer* device_ptr, std::string device_identifier, json &result)
{
/*
Interface type can be one of the followings:
Expand All @@ -259,10 +272,23 @@ void on_device_found(const DevicePointer* device_ptr, std::string device_identif
2 - wifi interface type
*/
int interface_type = AMDeviceGetInterfaceType(device_ptr->device_info);
if (interface_type == kUSBInterfaceType) {
devices[device_identifier] = { device_ptr->device_info, nullptr };
result[kEventString] = eventString;
get_device_properties(device_identifier, result);
if (interface_type == kUSBInterfaceType || interface_type == kWIFIInterfaceType) {
if (devices.count(device_identifier)) {
devices[device_identifier].device_info = device_ptr->device_info;
result[kEventString] = kDeviceUpdated;
} else {
devices[device_identifier] = { device_ptr->device_info, nullptr };
result[kEventString] = kDeviceFound;
}


if (interface_type == kUSBInterfaceType) {
devices[device_identifier].isUSBConnected = 1;
} else {
devices[device_identifier].isWiFiConnected = 1;
}

update_device_result(device_identifier, result);
}
}

Expand All @@ -275,21 +301,33 @@ void device_notification_callback(const DevicePointer* device_ptr)
{
case kADNCIMessageConnected:
{
on_device_found(device_ptr, device_identifier, kDeviceFound, result);
on_device_found(device_ptr, device_identifier, result);
break;
}
case kADNCIMessageDisconnected:
{
if (devices.count(device_identifier))
{
if (devices[device_identifier].apps_cache.size())
{
cleanup_file_resources(device_identifier);
if (devices.count(device_identifier)) {
int interface_type = AMDeviceGetInterfaceType(device_ptr->device_info);
if (interface_type == kUSBInterfaceType) {
devices[device_identifier].isUSBConnected = 0;
} else if (interface_type == kWIFIInterfaceType) {
devices[device_identifier].isWiFiConnected = 0;
}

if (!devices[device_identifier].isUSBConnected && !devices[device_identifier].isWiFiConnected) {
if (devices[device_identifier].apps_cache.size())
{
cleanup_file_resources(device_identifier);
}

devices.erase(device_identifier);
devices.erase(device_identifier);
result[kEventString] = kDeviceLost;
} else {
result[kEventString] = kDeviceUpdated;
update_device_result(device_identifier, result);
}
}
result[kEventString] = kDeviceLost;

break;
}
case kADNCIMessageUnknown:
Expand All @@ -299,7 +337,7 @@ void device_notification_callback(const DevicePointer* device_ptr)
}
case kADNCIMessageTrusted:
{
on_device_found(device_ptr, device_identifier, kDeviceTrusted, result);
on_device_found(device_ptr, device_identifier, result);
break;
}
}
Expand Down Expand Up @@ -497,14 +535,16 @@ void uninstall_application(std::string application_identifier, std::string devic
return;
}

HANDLE socket = start_secure_service(device_identifier, kInstallationProxy, method_id, true, false).socket;
if (!socket)
ServiceInfo serviceInfo = start_secure_service(device_identifier, kInstallationProxy, method_id, true, false);
if (!serviceInfo.socket)
{
return;
}

CFStringRef appid_cfstring = create_CFString(application_identifier.c_str());
unsigned result = AMDeviceUninstallApplication(socket, appid_cfstring, NULL, [] {}, NULL);
DeviceInfo* deviceInfo = devices[device_identifier].device_info;
CFDictionaryRef params = CFDictionaryCreate(NULL, {}, {}, 0, NULL, NULL);
unsigned result = AMDeviceSecureUninstallApplication(serviceInfo.connection, deviceInfo, appid_cfstring, params, NULL);
CFRelease(appid_cfstring);

if (result)
Expand Down Expand Up @@ -1137,7 +1177,7 @@ void post_notification(std::string device_identifier, PostNotificationInfo post_
void await_notification_response(std::string device_identifier, AwaitNotificationResponseInfo await_notification_response_info, std::string method_id)
{
ServiceConnRef connection = serviceConnections[(int)await_notification_response_info.socket];
std::string invalid_connection_error_message = "Invalid connectionId: " + std::to_string(await_notification_response_info.socket);
std::string invalid_connection_error_message = "Invalid socket: " + std::to_string(await_notification_response_info.socket);
PRINT_ERROR_AND_RETURN_IF_FAILED_RESULT(connection == nullptr, invalid_connection_error_message.c_str(), device_identifier, method_id);

ServiceInfo currentNotificationProxy = devices[device_identifier].services[kNotificationProxy];
Expand Down
2 changes: 2 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,8 @@ const dl = new DeviceLib.IOSDeviceLib(device => {
console.log("An error occurred ;(", err);
});
});
}, device => {
console.log("Device UPDATED!", device);
}, device => {
console.log("Device LOST!", device);
});
Expand Down
2 changes: 2 additions & 0 deletions constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,12 @@

exports.DataEventName = "data";
exports.DeviceFoundEventName = "deviceFound";
exports.DeviceUpdatedEventName = "deviceUpdated";
exports.DeviceLostEventName = "deviceLost";

exports.DeviceEventEnum = {
kDeviceFound: "deviceFound",
kDeviceUpdated: "deviceUpdated",
kDeviceLost: "deviceLost",
kDeviceTrusted: "deviceTrusted",
kDeviceUnknown: "deviceUnknown"
Expand Down
3 changes: 3 additions & 0 deletions ios-device-lib-stdio-handler.js
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ class IOSDeviceLibStdioHandler extends EventEmitter {
case Constants.DeviceEventEnum.kDeviceFound:
this.emit(Constants.DeviceFoundEventName, message);
break;
case Constants.DeviceEventEnum.kDeviceUpdated:
this.emit(Constants.DeviceUpdatedEventName, message);
break;
case Constants.DeviceEventEnum.kDeviceLost:
this.emit(Constants.DeviceLostEventName, message);
break;
Expand Down
3 changes: 2 additions & 1 deletion ios-device-lib.js
Original file line number Diff line number Diff line change
Expand Up @@ -27,12 +27,13 @@ const Events = {
};

class IOSDeviceLib extends EventEmitter {
constructor(onDeviceFound, onDeviceLost, options) {
constructor(onDeviceFound, onDeviceUpdated, onDeviceLost, options) {
super();
this._options = options || {};
this._iosDeviceLibStdioHandler = new IOSDeviceLibStdioHandler(this._options);
this._iosDeviceLibStdioHandler.startReadingData();
this._iosDeviceLibStdioHandler.on(Constants.DeviceFoundEventName, onDeviceFound);
this._iosDeviceLibStdioHandler.on(Constants.DeviceUpdatedEventName, onDeviceUpdated);
this._iosDeviceLibStdioHandler.on(Constants.DeviceLostEventName, onDeviceLost);
}

Expand Down
4 changes: 2 additions & 2 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "ios-device-lib",
"version": "0.6.0",
"version": "0.7.0",
"description": "",
"types": "./typings/ios-device-lib.d.ts",
"main": "index.js",
Expand Down Expand Up @@ -28,4 +28,4 @@
"istanbul": "0.4.5",
"mocha": "5.2.0"
}
}
}
4 changes: 3 additions & 1 deletion typings/interfaces.d.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@ declare global {
productType?: string;
productVersion?: string;
status?: string;
isUSBConnected: number;
isWiFiConnected: number;
}

interface IDeviceId {
Expand Down Expand Up @@ -132,7 +134,7 @@ declare global {
}

interface IOSDeviceLib extends NodeJS.EventEmitter {
new(onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib;
new(onDeviceFound: (found: IDeviceActionInfo) => void, onDeviceUpdated: (updated: IDeviceActionInfo) => void, onDeviceLost: (found: IDeviceActionInfo) => void): IOSDeviceLib;
install(ipaPath: string, deviceIdentifiers: string[]): Promise<IDeviceResponse>[];
uninstall(ipaPath: string, deviceIdentifiers: string[]): Promise<IDeviceResponse>[];
list(listArray: IReadOperationData[]): Promise<IDeviceMultipleResponse>[];
Expand Down