aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMarcus Tillmanns <[email protected]>2022-06-15 10:55:51 +0200
committerMarcus Tillmanns <[email protected]>2022-06-17 07:09:45 +0000
commite3fd840f98195a4f47ee7c9b3a2f27230eb3b099 (patch)
tree44885e1fd5d698d2cf794d53ef2725d1fa4b15fc
parentfd68b1c58ea654b4f218f1a32093b09301ea0e89 (diff)
iostool: Improve deployment speed using delta deploy
The iostool did always deploy the whole bundle, without taking into account whether anything has actually changed. This meant that for big bundles anytime the user starts the application on his device, a full deployment was done. For a ~1GB bundle this would take around a minute on a recent Mac and iPhone 12. This fix uses a new function from the mobiledevice framework called AMDeviceSecureInstallApplicationBundle. This function takes a new parameter "ShadowPathKey" which points to a directory where the last deploy state is captured temporarily. Before deploying to the device, the function compares what is to be deployed against the last deploy state and only deploys the parts that actually changed. QtCreator provides a temporary folder for this. Due to this, the initial deployment still does a complete deployment as no state is available yet. All subsequent deployments take the captured state into account. For backwards compatibility, the old deployment method is left intact. Fixes: QTCREATORBUG-24371 Change-Id: I4df6aa79d41b34c326d78be7952d7eeb23774648 Reviewed-by: Eike Ziller <[email protected]> Reviewed-by: <[email protected]> Reviewed-by: Qt CI Bot <[email protected]>
-rw-r--r--src/plugins/ios/iostoolhandler.cpp7
-rw-r--r--src/tools/iostool/CMakeLists.txt1
-rw-r--r--src/tools/iostool/cfutils.h55
-rw-r--r--src/tools/iostool/iosdevicemanager.cpp229
-rw-r--r--src/tools/iostool/iosdevicemanager.h2
-rw-r--r--src/tools/iostool/iostool.cpp8
-rw-r--r--src/tools/iostool/iostool.h1
-rw-r--r--src/tools/iostool/iostool.qbs1
-rw-r--r--src/tools/iostool/mobiledevicelib.cpp25
-rw-r--r--src/tools/iostool/mobiledevicelib.h9
10 files changed, 269 insertions, 69 deletions
diff --git a/src/plugins/ios/iostoolhandler.cpp b/src/plugins/ios/iostoolhandler.cpp
index c64a2731420..a3ccf2e5866 100644
--- a/src/plugins/ios/iostoolhandler.cpp
+++ b/src/plugins/ios/iostoolhandler.cpp
@@ -38,6 +38,7 @@
#include <utils/qtcassert.h>
#include <utils/qtcprocess.h>
#include <utils/runextensions.h>
+#include <utils/temporarydirectory.h>
#include <QCoreApplication>
#include <QDir>
@@ -701,10 +702,14 @@ void IosDeviceToolHandlerPrivate::requestTransferApp(const QString &bundlePath,
{
m_bundlePath = bundlePath;
m_deviceId = deviceId;
+ QString tmpDeltaPath = Utils::TemporaryDirectory::masterDirectoryFilePath().pathAppended("ios").toString();
QStringList args;
args << QLatin1String("--id") << deviceId << QLatin1String("--bundle")
<< bundlePath << QLatin1String("--timeout") << QString::number(timeout)
- << QLatin1String("--install");
+ << QLatin1String("--install")
+ << QLatin1String("--delta-path")
+ << tmpDeltaPath;
+
start(IosToolHandler::iosDeviceToolPath(), args);
}
diff --git a/src/tools/iostool/CMakeLists.txt b/src/tools/iostool/CMakeLists.txt
index e02bf7463d4..b7efdc1abda 100644
--- a/src/tools/iostool/CMakeLists.txt
+++ b/src/tools/iostool/CMakeLists.txt
@@ -18,6 +18,7 @@ add_qtc_executable(iostool
main.cpp
mobiledevicelib.cpp mobiledevicelib.h
relayserver.cpp relayserver.h
+ cfutils.h
)
if (TARGET iostool)
diff --git a/src/tools/iostool/cfutils.h b/src/tools/iostool/cfutils.h
new file mode 100644
index 00000000000..94e8452f0ce
--- /dev/null
+++ b/src/tools/iostool/cfutils.h
@@ -0,0 +1,55 @@
+/****************************************************************************
+**
+** Copyright (C) 2022 The Qt Company Ltd.
+** Contact: https://www.qt.io/licensing/
+**
+** This file is part of Qt Creator.
+**
+** Commercial License Usage
+** Licensees holding valid commercial Qt licenses may use this file in
+** accordance with the commercial license agreement provided with the
+** Software or, alternatively, in accordance with the terms contained in
+** a written agreement between you and The Qt Company. For licensing terms
+** and conditions see https://www.qt.io/terms-conditions. For further
+** information use the contact form at https://www.qt.io/contact-us.
+**
+** GNU General Public License Usage
+** Alternatively, this file may be used under the terms of the GNU
+** General Public License version 3 as published by the Free Software
+** Foundation with exceptions as appearing in the file LICENSE.GPL3-EXCEPT
+** included in the packaging of this file. Please review the following
+** information to ensure the GNU General Public License requirements will
+** be met: https://www.gnu.org/licenses/gpl-3.0.html.
+**
+****************************************************************************/
+
+#pragma once
+
+#include <QString>
+
+#include <CoreFoundation/CoreFoundation.h>
+
+namespace Ios {
+
+template<typename CFType>
+struct CFRefDeleter
+{
+ using pointer = CFType;
+ void operator()(CFType ref) { CFRelease(ref); }
+};
+
+inline QString toQStringRelease(CFStringRef str)
+{
+ QString result = QString::fromCFString(str);
+ CFRelease(str);
+ return result;
+}
+
+using CFString_t = std::unique_ptr<CFStringRef, CFRefDeleter<CFStringRef>>;
+using CFUrl_t = std::unique_ptr<CFURLRef, CFRefDeleter<CFURLRef>>;
+using CFPropertyList_t = std::unique_ptr<CFPropertyListRef, CFRefDeleter<CFPropertyListRef>>;
+using CFBundle_t = std::unique_ptr<CFBundleRef, CFRefDeleter<CFBundleRef>>;
+using CFDictionary_t = std::unique_ptr<CFDictionaryRef, CFRefDeleter<CFDictionaryRef>>;
+using CFArray_t = std::unique_ptr<CFArrayRef, CFRefDeleter<CFArrayRef>>;
+
+} // namespace Ios
diff --git a/src/tools/iostool/iosdevicemanager.cpp b/src/tools/iostool/iosdevicemanager.cpp
index 2e6aa4ccf36..781420beeb0 100644
--- a/src/tools/iostool/iosdevicemanager.cpp
+++ b/src/tools/iostool/iosdevicemanager.cpp
@@ -25,19 +25,19 @@
#include "iosdevicemanager.h"
+#include "cfutils.h"
#include "mobiledevicelib.h"
-#include <QDebug>
#include <QDir>
#include <QFile>
#include <QHash>
#include <QLibrary>
+#include <QLoggingCategory>
#include <QMultiHash>
#include <QMutex>
#include <QMutexLocker>
#include <QProcess>
#include <QRegularExpression>
-#include <QRegularExpression>
#include <QSettings>
#include <QThread>
#include <QTimer>
@@ -54,6 +54,10 @@ static const bool debugAll = false;
static const bool verbose = true;
static const bool noWifi = true;
+namespace {
+ Q_LOGGING_CATEGORY(loggingCategory, "qtc.iostool.iosdevicemanager", QtWarningMsg)
+}
+
// ------- MobileDeviceLib interface --------
namespace {
@@ -277,8 +281,12 @@ public:
static IosDeviceManagerPrivate *instance();
explicit IosDeviceManagerPrivate (IosDeviceManager *q);
bool watchDevices();
- void requestAppOp(const QString &bundlePath, const QStringList &extraArgs,
- Ios::IosDeviceManager::AppOp appOp, const QString &deviceId, int timeout);
+ void requestAppOp(const QString &bundlePath,
+ const QStringList &extraArgs,
+ Ios::IosDeviceManager::AppOp appOp,
+ const QString &deviceId,
+ int timeout,
+ const QString &deltaPath);
void requestDeviceInfo(const QString &deviceId, int timeout);
QStringList errors();
void addError(QString errorMsg);
@@ -321,13 +329,17 @@ public:
QString bundlePath;
QStringList extraArgs;
Ios::IosDeviceManager::AppOp appOp;
+ QString deltaPath;
-
- AppOpSession(const QString &deviceId, const QString &bundlePath,
- const QStringList &extraArgs, Ios::IosDeviceManager::AppOp appOp);
+ AppOpSession(const QString &deviceId,
+ const QString &bundlePath,
+ const QStringList &extraArgs,
+ Ios::IosDeviceManager::AppOp appOp,
+ const QString &deltaPath);
void deviceCallbackReturned() override;
bool installApp();
+ bool installAppNew();
bool runApp();
int qmljsDebugPort() const override;
am_res_t appTransferCallback(CFDictionaryRef dict) override;
@@ -486,11 +498,13 @@ bool IosDeviceManagerPrivate::watchDevices()
}
void IosDeviceManagerPrivate::requestAppOp(const QString &bundlePath,
- const QStringList &extraArgs,
- IosDeviceManager::AppOp appOp,
- const QString &deviceId, int timeout)
+ const QStringList &extraArgs,
+ IosDeviceManager::AppOp appOp,
+ const QString &deviceId,
+ int timeout,
+ const QString &deltaPath)
{
- AppOpSession *session = new AppOpSession(deviceId, bundlePath, extraArgs, appOp);
+ AppOpSession *session = new AppOpSession(deviceId, bundlePath, extraArgs, appOp, deltaPath);
session->startDeviceLookup(timeout);
}
@@ -1205,10 +1219,17 @@ bool CommandSession::developerDiskImagePath(QString *path, QString *signaturePat
return false;
}
-AppOpSession::AppOpSession(const QString &deviceId, const QString &bundlePath,
- const QStringList &extraArgs, IosDeviceManager::AppOp appOp):
- CommandSession(deviceId), bundlePath(bundlePath), extraArgs(extraArgs), appOp(appOp)
-{ }
+AppOpSession::AppOpSession(const QString &deviceId,
+ const QString &bundlePath,
+ const QStringList &extraArgs,
+ IosDeviceManager::AppOp appOp,
+ const QString &deltaPath)
+ : CommandSession(deviceId)
+ , bundlePath(bundlePath)
+ , extraArgs(extraArgs)
+ , appOp(appOp)
+ , deltaPath(deltaPath)
+{}
QString AppOpSession::commandName()
{
@@ -1218,72 +1239,145 @@ QString AppOpSession::commandName()
bool AppOpSession::installApp()
{
bool success = false;
- if (device != 0) {
- CFURLRef bundleUrl = QUrl::fromLocalFile(bundlePath).toCFURL();
- CFStringRef key[1] = {CFSTR("PackageType")};
- CFStringRef value[1] = {CFSTR("Developer")};
- CFDictionaryRef options = CFDictionaryCreate(0, reinterpret_cast<const void**>(&key[0]),
- reinterpret_cast<const void**>(&value[0]), 1,
- &kCFTypeDictionaryKeyCallBacks,
- &kCFTypeDictionaryValueCallBacks);
+ if (device) {
+ if (!installAppNew()) {
+ addError(QString::fromLatin1(
+ "Failed to transfer and install application, trying old way ..."));
- MobileDeviceLib &mLib = MobileDeviceLib::instance();
- // Transfer bundle with secure API AMDeviceTransferApplication.
- if (int error = mLib.deviceSecureTransferApplicationPath(0, device, bundleUrl, options,
- &appSecureTransferSessionCallback,0)) {
- addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, AMDeviceTransferApplication returned %3 (0x%4)")
- .arg(bundlePath, deviceId).arg(mobileDeviceErrorString(error)).arg(error));
- success = false;
- } else {
- // App is transferred. Try installing.
- if (connectDevice()) {
- // Secure install app api requires device to be connected.
- if (am_res_t error = mLib.deviceSecureInstallApplication(0, device, bundleUrl, options,
- &appSecureTransferSessionCallback,0)) {
- const QString errorString = mobileDeviceErrorString(error);
- if (!errorString.isEmpty()) {
- addError(errorString
- + QStringLiteral(" (0x")
- + QString::number(error, 16)
- + QStringLiteral(")"));
+ const CFUrl_t bundleUrl(QUrl::fromLocalFile(bundlePath).toCFURL());
+ MobileDeviceLib &mLib = MobileDeviceLib::instance();
+
+ CFStringRef key[1] = {CFSTR("PackageType")};
+ CFStringRef value[1] = {CFSTR("Developer")};
+ const CFDictionary_t options(
+ CFDictionaryCreate(0,
+ reinterpret_cast<const void **>(&key[0]),
+ reinterpret_cast<const void **>(&value[0]),
+ 1,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ // Transfer bundle with secure API AMDeviceTransferApplication.
+ if (int error
+ = mLib.deviceSecureTransferApplicationPath(0,
+ device,
+ bundleUrl.get(),
+ options.get(),
+ &appSecureTransferSessionCallback,
+ 0)) {
+ addError(QString::fromLatin1("TransferAppSession(%1,%2) failed, "
+ "AMDeviceTransferApplication returned %3 (0x%4)")
+ .arg(bundlePath, deviceId)
+ .arg(mobileDeviceErrorString(error))
+ .arg(error));
+ success = false;
+ } else {
+ // App is transferred. Try installing.
+ if (connectDevice()) {
+ // Secure install app api requires device to be connected.
+ if (am_res_t error
+ = mLib.deviceSecureInstallApplication(0,
+ device,
+ bundleUrl.get(),
+ options.get(),
+ &appSecureTransferSessionCallback,
+ 0)) {
+ const QString errorString = mobileDeviceErrorString(error);
+ if (!errorString.isEmpty()) {
+ addError(errorString + QStringLiteral(" (0x")
+ + QString::number(error, 16) + QStringLiteral(")"));
+ } else {
+ addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, "
+ "AMDeviceInstallApplication returned 0x%3")
+ .arg(bundlePath, deviceId)
+ .arg(QString::number(error, 16)));
+ }
+ success = false;
} else {
- addError(QString::fromLatin1("InstallAppSession(%1,%2) failed, "
- "AMDeviceInstallApplication returned 0x%3")
- .arg(bundlePath, deviceId).arg(QString::number(error, 16)));
+ // App is installed.
+ success = true;
}
- success = false;
- } else {
- // App is installed.
- success = true;
+ disconnectDevice();
}
- disconnectDevice();
}
+ } else {
+ success = true;
}
- if (debugAll) {
- qDebug() << "AMDeviceSecureTransferApplication finished request with " << (success ? "Success" : "Failure");
- }
-
- CFRelease(options);
- CFRelease(bundleUrl);
+ qCDebug(loggingCategory) << "AMDeviceSecureTransferApplication finished request with"
+ << (success ? "Success" : "Failure");
progressBase += 100;
}
-
if (success) {
sleep(5); // after installation the device needs a bit of quiet....
}
- if (debugAll) {
- qDebug() << "AMDeviceSecureInstallApplication finished request with " << (success ? "Success" : "Failure");
- }
+ qCDebug(loggingCategory) << "AMDeviceSecureInstallApplication finished request with"
+ << (success ? "Success" : "Failure");
- IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath, deviceId,
- (success ? IosDeviceManager::Success : IosDeviceManager::Failure));
+ IosDeviceManagerPrivate::instance()->didTransferApp(bundlePath,
+ deviceId,
+ (success ? IosDeviceManager::Success
+ : IosDeviceManager::Failure));
return success;
}
+bool AppOpSession::installAppNew()
+{
+ const CFUrl_t bundleUrl(QUrl::fromLocalFile(bundlePath).toCFURL());
+ MobileDeviceLib &mLib = MobileDeviceLib::instance();
+
+ CFBundle_t bundle(CFBundleCreate(kCFAllocatorDefault, bundleUrl.get()));
+
+ if (!bundle) {
+ addError(QString::fromLatin1("Failed to create bundle"));
+ return false;
+ }
+
+ const CFString_t bundleId(CFBundleGetIdentifier(bundle.get()));
+ if (!bundleId) {
+ addError(QString::fromLatin1("Failed to retrieve bundle id"));
+ return false;
+ }
+
+ CFUrl_t dpath(QUrl::fromLocalFile(deltaPath).toCFURL());
+
+ CFStringRef keys[] = {
+ CFSTR("CFBundleIdentifier"),
+ CFSTR("CloseOnInvalidate"),
+ CFSTR("InvalidateOnDetach"),
+ CFSTR("IsUserInitiated"),
+ CFSTR("PackageType"),
+ CFSTR("PreferWifi"),
+ CFSTR("ShadowParentKey"),
+ };
+ CFStringRef values[] = {bundleId.get(),
+ CFSTR("1"),
+ CFSTR("1"),
+ CFSTR("1"),
+ CFSTR("Developer"),
+ CFSTR("1"),
+ (CFStringRef)dpath.get()};
+
+ const CFDictionary_t options(CFDictionaryCreate(0,
+ reinterpret_cast<const void **>(&keys[0]),
+ reinterpret_cast<const void **>(&values[0]),
+ 7,
+ &kCFTypeDictionaryKeyCallBacks,
+ &kCFTypeDictionaryValueCallBacks));
+
+ if (int error = mLib.deviceSecureInstallApplicationBundle(0,
+ device,
+ bundleUrl.get(),
+ options.get(),
+ &appSecureTransferSessionCallback))
+ return false;
+
+ return true;
+}
+
void AppOpSession::deviceCallbackReturned()
{
switch (appOp) {
@@ -1575,9 +1669,14 @@ bool IosDeviceManager::watchDevices() {
return d->watchDevices();
}
-void IosDeviceManager::requestAppOp(const QString &bundlePath, const QStringList &extraArgs,
- AppOp appOp, const QString &deviceId, int timeout) {
- d->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout);
+void IosDeviceManager::requestAppOp(const QString &bundlePath,
+ const QStringList &extraArgs,
+ AppOp appOp,
+ const QString &deviceId,
+ int timeout,
+ QString deltaPath)
+{
+ d->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout, deltaPath);
}
void IosDeviceManager::requestDeviceInfo(const QString &deviceId, int timeout)
diff --git a/src/tools/iostool/iosdevicemanager.h b/src/tools/iostool/iosdevicemanager.h
index 7c521c789fd..2fb3bb1c3a3 100644
--- a/src/tools/iostool/iosdevicemanager.h
+++ b/src/tools/iostool/iosdevicemanager.h
@@ -62,7 +62,7 @@ public:
static IosDeviceManager *instance();
bool watchDevices();
void requestAppOp(const QString &bundlePath, const QStringList &extraArgs, AppOp appOp,
- const QString &deviceId, int timeout = 1000);
+ const QString &deviceId, int timeout = 1000, QString deltaPath = QString());
void requestDeviceInfo(const QString &deviceId, int timeout = 1000);
int processGdbServer(ServiceConnRef conn);
void stopGdbServer(ServiceConnRef conn, int phase);
diff --git a/src/tools/iostool/iostool.cpp b/src/tools/iostool/iostool.cpp
index e65cae852a4..2def3afa74a 100644
--- a/src/tools/iostool/iostool.cpp
+++ b/src/tools/iostool/iostool.cpp
@@ -82,6 +82,12 @@ void IosTool::run(const QStringList &args)
printHelp = true;
}
bundlePath = args.value(iarg);
+ } else if (arg == QLatin1String("--delta-path")) {
+ if (++iarg == args.size()) {
+ writeMsg(QStringLiteral("missing path after ") + arg);
+ printHelp = true;
+ }
+ m_deltasPath = args.value(iarg);
} else if (arg == QLatin1String("--install")) {
appOp = IosDeviceManager::AppOp(appOp | IosDeviceManager::Install);
} else if (arg == QLatin1String("--run")) {
@@ -163,7 +169,7 @@ void IosTool::run(const QStringList &args)
break;
}
maxProgress = 200;
- manager->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout);
+ manager->requestAppOp(bundlePath, extraArgs, appOp, deviceId, timeout, m_deltasPath);
}
if (opLeft == 0)
doExit(0);
diff --git a/src/tools/iostool/iostool.h b/src/tools/iostool/iostool.h
index 6aa85216ca0..c71a30e6d8c 100644
--- a/src/tools/iostool/iostool.h
+++ b/src/tools/iostool/iostool.h
@@ -79,6 +79,7 @@ private:
Ios::IosDeviceManager::AppOp appOp;
QFile outFile;
QString m_qmlPort;
+ QString m_deltasPath;
QXmlStreamWriter out;
GdbRelayServer *gdbServer;
QmlRelayServer *qmlServer;
diff --git a/src/tools/iostool/iostool.qbs b/src/tools/iostool/iostool.qbs
index a39ace4dba1..bac9f43725f 100644
--- a/src/tools/iostool/iostool.qbs
+++ b/src/tools/iostool/iostool.qbs
@@ -11,6 +11,7 @@ QtcTool {
Depends { name: "app_version_header" }
files: [
+ "cfutils.h"
"Info.plist",
"gdbrunner.cpp",
"gdbrunner.h",
diff --git a/src/tools/iostool/mobiledevicelib.cpp b/src/tools/iostool/mobiledevicelib.cpp
index 025248262f1..ae1c70f4a86 100644
--- a/src/tools/iostool/mobiledevicelib.cpp
+++ b/src/tools/iostool/mobiledevicelib.cpp
@@ -89,7 +89,15 @@ bool MobileDeviceLib::load()
m_AMDSetLogLevel = reinterpret_cast<AMDSetLogLevelPtr>(lib.resolve("AMDSetLogLevel"));
if (m_AMDSetLogLevel == 0)
addError("MobileDeviceLib does not define AMDSetLogLevel");
- m_AMDeviceNotificationSubscribe = reinterpret_cast<AMDeviceNotificationSubscribePtr>(lib.resolve("AMDeviceNotificationSubscribe"));
+
+ m_AMDeviceSecureInstallApplicationBundle
+ = reinterpret_cast<AMDeviceSecureInstallApplicationBundlePtr>(
+ lib.resolve("AMDeviceSecureInstallApplicationBundle"));
+ if (m_AMDeviceSecureInstallApplicationBundle == 0)
+ addError("MobileDeviceLib does not define m_AMDeviceSecureInstallApplicationBundle");
+
+ m_AMDeviceNotificationSubscribe = reinterpret_cast<AMDeviceNotificationSubscribePtr>(
+ lib.resolve("AMDeviceNotificationSubscribe"));
if (m_AMDeviceNotificationSubscribe == 0)
addError("MobileDeviceLib does not define AMDeviceNotificationSubscribe");
m_AMDeviceNotificationUnsubscribe = reinterpret_cast<AMDeviceNotificationUnsubscribePtr>(lib.resolve("AMDeviceNotificationUnsubscribe"));
@@ -358,6 +366,21 @@ int MobileDeviceLib::deviceSecureTransferApplicationPath(int zero, AMDeviceRef d
return returnCode;
}
+int MobileDeviceLib::deviceSecureInstallApplicationBundle(
+ int zero,
+ AMDeviceRef device,
+ CFURLRef url,
+ CFDictionaryRef options,
+ AMDeviceSecureInstallApplicationCallback callback)
+{
+ int returnCode = -1;
+
+ if (m_AMDeviceSecureInstallApplicationBundle) {
+ returnCode = m_AMDeviceSecureInstallApplicationBundle(device, url, options, callback, zero);
+ }
+ return returnCode;
+}
+
int MobileDeviceLib::deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url, CFDictionaryRef options, AMDeviceSecureInstallApplicationCallback callback, int arg)
{
int returnCode = -1;
diff --git a/src/tools/iostool/mobiledevicelib.h b/src/tools/iostool/mobiledevicelib.h
index 97735fdcb1a..68bca9d316d 100644
--- a/src/tools/iostool/mobiledevicelib.h
+++ b/src/tools/iostool/mobiledevicelib.h
@@ -101,6 +101,7 @@ typedef am_res_t (MDEV_API *USBMuxConnectByPortPtr)(unsigned int, int, ServiceSo
// secure Api's
typedef am_res_t (MDEV_API *AMDeviceSecureStartServicePtr)(AMDeviceRef, CFStringRef, unsigned int *, ServiceConnRef *);
typedef int (MDEV_API *AMDeviceSecureTransferPathPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int);
+typedef int (MDEV_API *AMDeviceSecureInstallApplicationBundlePtr)(AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int zero);
typedef int (MDEV_API *AMDeviceSecureInstallApplicationPtr)(int, AMDeviceRef, CFURLRef, CFDictionaryRef, AMDeviceSecureInstallApplicationCallback, int);
typedef int (MDEV_API *AMDServiceConnectionGetSocketPtr)(ServiceConnRef);
@@ -158,6 +159,13 @@ public:
int deviceSecureTransferApplicationPath(int, AMDeviceRef, CFURLRef,
CFDictionaryRef,
AMDeviceSecureInstallApplicationCallback callback, int);
+
+ int deviceSecureInstallApplicationBundle(int zero,
+ AMDeviceRef device,
+ CFURLRef url,
+ CFDictionaryRef options,
+ AMDeviceSecureInstallApplicationCallback callback);
+
int deviceSecureInstallApplication(int zero, AMDeviceRef device, CFURLRef url,
CFDictionaryRef options,
AMDeviceSecureInstallApplicationCallback callback, int arg);
@@ -191,6 +199,7 @@ private:
AMDeviceMountImagePtr m_AMDeviceMountImage;
AMDeviceSecureStartServicePtr m_AMDeviceSecureStartService;
AMDeviceSecureTransferPathPtr m_AMDeviceSecureTransferPath;
+ AMDeviceSecureInstallApplicationBundlePtr m_AMDeviceSecureInstallApplicationBundle;
AMDeviceSecureInstallApplicationPtr m_AMDeviceSecureInstallApplication;
AMDServiceConnectionGetSocketPtr m_AMDServiceConnectionGetSocket;
AMDServiceConnectionSendPtr m_AMDServiceConnectionSend;