Add uninstall feature.
diff --git a/MobileDevice.h b/MobileDevice.h
index 837cfd4..e078a44 100644
--- a/MobileDevice.h
+++ b/MobileDevice.h
@@ -453,6 +453,8 @@
mach_error_t AMDeviceInstallApplication(service_conn_t socket, CFStringRef path, CFDictionaryRef options, am_device_install_application_callback callback, void *user);
mach_error_t AMDeviceTransferApplication(service_conn_t socket, CFStringRef path, CFDictionaryRef options, am_device_install_application_callback callbackj, void *user);
+int AMDeviceSecureUninstallApplication(int unknown0, struct am_device *device, CFStringRef bundle_id, int unknown1, void *callback, int callback_arg);
+
/* ----------------------------------------------------------------------------
* Semi-private routines
* ------------------------------------------------------------------------- */
diff --git a/ios-deploy.c b/ios-deploy.c
index cadaaed..ebf80fc 100644
--- a/ios-deploy.c
+++ b/ios-deploy.c
@@ -125,7 +125,7 @@
int AMDeviceMountImage(AMDeviceRef device, CFStringRef image, CFDictionaryRef options, void *callback, int cbarg);
mach_error_t AMDeviceLookupApplications(AMDeviceRef device, CFDictionaryRef options, CFDictionaryRef *result);
-bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, detect_only = false, install = true;
+bool found_device = false, debug = false, verbose = false, unbuffered = false, nostart = false, detect_only = false, install = true, uninstall = false;
bool interactive = true;
char *app_path = NULL;
char *device_id = NULL;
@@ -813,6 +813,42 @@
}
}
+CFStringRef get_bundle_id(CFURLRef app_url)
+{
+ if (app_url == NULL)
+ return NULL;
+
+ CFURLRef url = CFURLCreateCopyAppendingPathComponent(NULL, app_url, CFSTR("Info.plist"), false);
+
+ if (url == NULL)
+ return NULL;
+
+ CFReadStreamRef stream = CFReadStreamCreateWithFile(NULL, url);
+ CFRelease(url);
+
+ if (stream == NULL)
+ return NULL;
+
+ CFPropertyListRef plist = NULL;
+ if (CFReadStreamOpen(stream) == TRUE) {
+ plist = CFPropertyListCreateWithStream(NULL, stream, 0,
+ kCFPropertyListImmutable, NULL, NULL);
+ }
+ CFReadStreamClose(stream);
+ CFRelease(stream);
+
+ if (plist == NULL)
+ return NULL;
+
+ const void *value = CFDictionaryGetValue(plist, CFSTR("CFBundleIdentifier"));
+ CFStringRef bundle_id = NULL;
+ if (value != NULL)
+ bundle_id = CFRetain(value);
+
+ CFRelease(plist);
+ return bundle_id;
+}
+
void handle_device(AMDeviceRef device) {
if (found_device) return; // handle one device only
CFStringRef found_device_id = AMDeviceCopyDeviceIdentifier(device);
@@ -841,7 +877,29 @@
CFRelease(relative_url);
+ if (uninstall) {
+ printf("------ Uninstall phase ------\n");
+
+ CFStringRef bundle_id = get_bundle_id(url);
+ if (bundle_id == NULL) {
+ printf("Error: Unable to get bundle id from package %s\n Uninstall failed\n", app_path);
+ } else {
+ AMDeviceConnect(device);
+ assert(AMDeviceIsPaired(device));
+ assert(AMDeviceValidatePairing(device) == 0);
+ assert(AMDeviceStartSession(device) == 0);
+
+ assert(AMDeviceSecureUninstallApplication(0, device, bundle_id, 0, NULL, 0) == 0);
+
+ assert(AMDeviceStopSession(device) == 0);
+ assert(AMDeviceDisconnect(device) == 0);
+
+ printf("[ OK ] Uninstalled package with bundle id %s\n", CFStringGetCStringPtr(bundle_id, CFStringGetSystemEncoding()));
+ }
+ }
+
if(install) {
+ printf("------ Install phase ------\n");
printf("[ 0%%] Found device (%s), beginning install\n", CFStringGetCStringPtr(found_device_id, CFStringGetSystemEncoding()));
AMDeviceConnect(device);
@@ -929,6 +987,7 @@
" -v, --verbose enable verbose output\n"
" -m, --noinstall directly start debugging without app install (-d not required)\n"
" -p, --port <number> port used for device, default: 12345 \n"
+ " -r, --uninstall uninstall the app before install (do not use with -m; app cache and data are cleared) \n"
" -V, --version print the executable version \n",
app);
}
@@ -953,11 +1012,12 @@
{ "version", no_argument, NULL, 'V' },
{ "noinstall", no_argument, NULL, 'm' },
{ "port", required_argument, NULL, 'p' },
+ { "uninstall", no_argument, NULL, 'r' },
{ NULL, 0, NULL, 0 },
};
char ch;
- while ((ch = getopt_long(argc, argv, "VmcdvunIi:b:a:t:g:x:p:", longopts, NULL)) != -1)
+ while ((ch = getopt_long(argc, argv, "VmcdvunrIi:b:a:t:g:x:p:", longopts, NULL)) != -1)
{
switch (ch) {
case 'm':
@@ -1000,6 +1060,9 @@
case 'p':
port = atoi(optarg);
break;
+ case 'r':
+ uninstall = 1;
+ break;
default:
usage(argv[0]);
return exitcode_error;
@@ -1020,10 +1083,6 @@
timeout = 5;
}
- if (!detect_only) {
- printf("------ Install phase ------\n");
- }
-
if (app_path) {
assert(access(app_path, F_OK) == 0);
}