Обмен данными и сохранение данных между приложениями с помощью групп приложений

Вчера в iOS 8 был представлен новый API, касающийся групп приложений. Раньше было довольно грязно обмениваться данными и общаться между приложениями, и я считаю, что именно это и призваны исправить группы приложений.

В моем приложении я включил группы приложений и добавил новую группу, но я просто не могу найти документацию о том, как ее использовать. В документации и ссылках на API указано только, как добавить группу.

Итак, для чего на самом деле предназначены группы приложений? Есть ли где-нибудь документация о том, как его использовать?


person streem    schedule 03.06.2014    source источник


Ответы (6)


Еще одним преимуществом групп приложений является возможность совместного использования базы данных NSUserDefaults. Это также работает для расширений приложений (виджеты центра уведомлений, настраиваемые клавиатуры и т. д.).

Инициализируйте свой объект NSUserDefaults таким образом во всех приложениях в группе приложений, и они будут совместно использовать базу данных:

Цель-С:

[[NSUserDefaults alloc] initWithSuiteName:@"<group identifier>"];

Быстрый:

NSUserDefaults(suiteName: "<group identifier>")

Имейте в виду, что все из базы данных [NSUserDefaults standardUserDefaults] для каждого приложения не будет перенесено в эту базу данных.

документация также дает правильный пример (начиная с бета-версии 3).

И не забудьте синхронизировать базу данных:

[yourDefaults synchronize];
person Andrew    schedule 05.06.2014
comment
Работает только на симуляторе (XCode 6 beta 5, iOS 8 beta 5) - person iOS Dev; 13.08.2014
comment
ПРИМЕЧАНИЕ. Если вы используете это с расширением iOS 8 (например, клавиатурой), вам необходимо убедиться, что ваше расширение имеет значение RequestsOpenAccess=YES в файле Info.plist. - person Kiran Panesar; 27.08.2014
comment
Я сделал RequestsOpenAccess=YES и следую инструкциям, но он не работает для меня на устройстве и отлично работает на эмуляторе, что-то конкретное для устройства? - person MAC; 19.11.2014
comment
Та же проблема со мной, я интегрировал расширение общего доступа в свое приложение, оно работает на симуляторе, но не работает на реальном устройстве, я добавил RequestOpenAccess =YES, но это не работает, мой вопрос stackoverflow.com/questions/30489894/ - person Ravi Ojha; 29.05.2015
comment
@Tejinder Вы не предоставили никакой информации о том, как я могу диагностировать вашу проблему. Какую версию iOS вы используете? Скорее всего, вы столкнулись с проблемой подготовки, и вам следует проверить свои профили подготовки, чтобы убедиться, что они правильно настроены для групп приложений. - person Andrew; 18.06.2015
comment
Знаете ли вы, можно ли использовать одну и ту же группу приложений в двух разных организациях? Сможем ли мы использовать группу приложений в библиотеке, которую мы распространяем среди других организаций? - person Mike Richards; 26.01.2016
comment
@MikeRichards не уверен, но, если я правильно помню, группы приложений имеют префикс с идентификатором команды. - person Andrew; 26.01.2016
comment
@SantaClaus Да, у вас должен быть тот же идентификатор разработки команды, что и здесь: developer.apple.com/library/ios/documentation/Miscellaneous/ - person Bernard; 27.05.2016
comment
@SantaClaus Можем ли мы разрешить контейнер групп приложений для общего доступа к файлам iTunes Application supports iTunes file sharing? - person Sunil Targe; 06.12.2016

Обмен данными NSUserDefaults между несколькими приложениями

Чтобы иметь общие значения по умолчанию для приложения и расширения или между двумя приложениями, вы должны добавить группу приложений в свои настройки, выполнив следующие действия:

  1. В Project Navigator щелкните файл *.xcodeproj (должен быть вверху).
  2. Справа от навигатора проектов найдите Project и Targets. В разделе «Цели» нажмите на свою основную цель (должна быть первой в разделе «Цели»).
  3. В верхней части щелкните вкладку «Возможности».
  4. В разделе «Группы приложений» щелкните переключатель справа, чтобы включить группы приложений.
  5. Нажмите кнопку + и добавьте группу приложений с именем group.com.company.myApp.
  6. Перейдите в то же место в других ваших приложениях, и теперь эта группа должна быть доступна для выбора. Включите эту группу для каждого приложения, которое будет использовать эти общие данные.

Примечание. Если вы перейдете на портал Apple Developer Portal (веб-сайт Apple, на котором показаны все ваши сертификаты, идентификаторы, устройства и профили подготовки) и выберите «Идентификаторы» > «Группы приложений», вы должны увидеть эту новую группу приложений.

Чтобы сохранить данные:

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")!
userDefaults.setObject("user12345", forKey: "userId")
userDefaults.synchronize()

Чтобы получить данные:

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
if let testUserId = userDefaults?.objectForKey("userId") as? String {
  print("User Id: \(testUserId)")
}
person TenaciousJay    schedule 27.10.2015
comment
Спасибо! Потребовалось немного поиска в документации, чтобы понять, как это сделать, и я подумал, что другие могут оценить шаги, которые я предпринял. - person TenaciousJay; 05.02.2016
comment
Спасибо за подробное описание...! нам нужно создать какой-либо сертификат на портале разработчиков Apple (веб-сайт Apple, на котором показаны все ваши сертификаты, идентификаторы, устройства и профили подготовки), чтобы включить эту группу? то же самое, что и Push-уведомление.? - person Arbaz Shaikh; 21.03.2016
comment
Когда вы выполняете шаг 5, он должен добавить группу приложений на портал разработчиков Apple, вам не нужно переходить непосредственно на портал разработчиков, чтобы добавить ее. После того, как вы сделаете шаг 5, вы можете перейти на портал и увидеть, что он должен был создать его для вас. - person TenaciousJay; 22.03.2016
comment
@TenaciousJay Превосходный ответ. Просто хочу добавить Если вы хотите запустить приложение из приложения func (приложение: UIApplication, URL-адрес openURL: NSURL, параметры: [String: AnyObject]) -> Bool - person Taimur Ajmal; 09.10.2016
comment
отличный ответ. спасибо @TenaciousJay. Я пытаюсь получить переменную и ее значение из AppB в AppA, как мне это сделать? Например, если riderCancelledRequest = true в AppB, как мне получить это в AppA? - person LizG; 19.01.2017
comment
В Swift 3.0, поскольку вы не храните объект, вы, вероятно, использовали бы set вместо setObject. Таким образом, в AppB он будет включать строку: userDefaults!.set(true, forKey: riderCancelledRequest). А в AppA включить строку: userDefaults?.bool(forKey: riderCancelledRequest). - person TenaciousJay; 19.01.2017
comment
Есть ли какой-либо другой процесс для загрузки приложений? Я анализирую данные между Native iOS и приложением Unity. - person Krunal Nagvadia; 06.09.2019
comment
На сегодняшний день лучшее решение. Это должен быть принятый ответ - person eharo2; 15.05.2020

Группы приложений, согласно моей интерпретации существующей документации, в первую очередь предназначены для расширений, точнее, для виджетов. Виджеты — это собственные пакеты приложений, которые сосуществуют с вашим приложением. Поскольку они представляют собой отдельное приложение и, следовательно, имеют собственную песочницу, вам нужно будет использовать группы приложений для обмена файлами.

После некоторой обработки заголовков я думаю, что нашел необходимый API, но на самом деле он был включен как часть iOS 7.

NSFileManager имеет метод containerURLForSecurityApplicationGroupIdentifier:, где вы можете передать идентификатор, созданный вами при включении групп приложений для ваших приложений:

NSURL *containerURL = [[NSFileManager defaultManager] 
           containerURLForSecurityApplicationGroupIdentifier:@"group.com.company.app"];
person Wayne Hartman    schedule 04.06.2014
comment
Спасибо, я считаю, что вы правы насчет расширяемости. Я немного более сомневаюсь в этом методе iOS 7, он кажется мне довольно статичным, iOS 8 представила реальные взаимодействия и связь между приложениями. - person streem; 04.06.2014
comment
@Justafinger Этот метод iOS 7 предназначен только для создания URL-адреса для записи и чтения данных между общими приложениями. Этот конкретный метод действительно полезен (из того, что я вижу до сих пор) только для виджетов, но не для других расширений. - person Wayne Hartman; 04.06.2014
comment
Что ж, я считаю, что Apple хотела упростить это в iOS 8 без необходимости программно создавать контейнер и делиться пользовательскими файлами. В документации указано, что вы должны возможность обмениваться данными с помощью NSUserDefault. Думаю, я что-то упускаю, потому что это не работает для меня. - person streem; 04.06.2014
comment
@Justafinger Я тоже не смог заставить NSUserDefaults работать. Я отношусь к ошибке до Beta 1. - person Wayne Hartman; 04.06.2014
comment
@WayneHartman Существует обходной путь для базы данных NSUserDefaults. Смотрите мой ответ. - person Andrew; 05.06.2014

Одна важная ловушка, на которую я сегодня наткнулся, заключается в следующем:

Во многих проектах я видел одно целевое приложение с разными идентификаторами пакета, установленными для каждой конфигурации этой цели. Здесь все становится грязным. Разработчики намеревались создать приложение отладки для конфигурации отладки и рабочее приложение для цели выпуска.

Если вы сделаете это, оба приложения будут использовать одни и те же NSUserDefaults, когда они настроены таким образом.

var userDefaults = NSUserDefaults(suiteName: "group.com.company.myApp")
userDefaults!.setObject("user12345", forKey: "userId")
userDefaults!.synchronize()

Это вызывает проблемы во многих местах:

  1. Представьте, что вы установили YES для клавиши, когда пользователю был показан специальный вводной экран приложения. Другое приложение теперь также будет читать YES и не будет показывать вступление.
  2. Да, некоторые приложения также хранят токены oAuth в своих пользовательских настройках по умолчанию. В любом случае... В зависимости от реализации приложение распознает наличие токена и начнет извлекать данные, используя неправильный токен. Велика вероятность того, что это завершится ошибкой со странными ошибками.

В общем случае решение этой проблемы состоит в том, чтобы добавить к ключам по умолчанию префикс текущей созданной конфигурации. Вы можете легко определить конфигурацию во время выполнения, установив различные идентификаторы пакетов для своих конфигураций. Затем просто прочитайте идентификатор пакета из NSBundle.mainBundle(). Если у вас одинаковые идентификаторы пакетов, вам нужно установить разные макросы препроцессора, например

#ifdef DEBUG
  NSString* configuration = @"debug";
#elif RELEASE
  NSString* configuration = @"release";
#endif

В Swift это будет выглядеть почти так же:

#if DEBUG
  let configuration = "debug"
#elseif RELEASE
  let configuration = "release"
#endif
person blackjacx    schedule 10.12.2015
comment
Ваши проблемы существуют из-за того, что вы смешиваете все свои данные в общем файле UserDefaults. Вы должны использовать NSUserDefaults.standardUserDefaults() для данных, которыми нельзя делиться. - person Daniel; 22.02.2016

Для хранения

let shared: NSUserDefaults = NSUserDefaults(suiteName: "group.abcapp")!
shared.setObject("abc.png", forKey: "favEmoji")
shared.synchronize()
person Hardik Thakkar    schedule 06.09.2016

App Group позволяет вам обмениваться данными (UserDefaults, Files, CoreData (управление графиком модели), блокировками POSIX) между различными процессами (приложениями, расширениями...) из одной и той же команды разработчиков (учетной записи). Он создает shared container с id, который должен начинаться с group. для сохранения/кеширования данных, к которым вам разрешен доступ, URL-адрес мысли и IPC.

Чтобы использовать App Group с UserDefaults

  1. Добавьте возможность App Group с одним и тем же идентификатором для ВСЕХ целей (приложение, расширение...), к которым вы получите доступ из введите здесь описание изображения

После создания вы можете проверить его на Apple Developer. Сертификаты, идентификаторы и профили -> Идентификаторы -> ВСЕ группы

введите здесь описание изображения

  1. Запись из Application1
let defaults = UserDefaults(suiteName: "group.goforit")
defaults?.setValue("Hello World!", forKey: "key1")
  1. Чтение из Application2
let defaults = UserDefaults(suiteName: "group.goforit")
let result = defaults?.value(forKey: "key1") //Hello World!

shared container одиночный URL-адрес корневого местоположения.

let rootURL = FileManager.default.containerURL(forSecurityApplicationGroupIdentifier: "group.goforit")

//file:///Users/alex/Library/Developer/CoreSimulator/Devices/1AF41817-FE2E-485A-A592-12C39C0B0141/data/Containers/Shared/AppGroup/DC14D43F-2C2C-4771-83BE-64A9F54BD2E1/
person yoAlex5    schedule 03.03.2021