the ios sdk could not be found что делать
Устранение неполадок пакета SDK для iOS
Проблемы во время установки
Данные аналитики не отображаются на портале
Убедитесь, что модули SDK интегрированы правильно.
Если вы хотите просмотреть журналы, отправляемые на серверную часть, измените уровень ведения журнала на подробный в приложении. Пакет SDK выполнит печать журналов в консоли. Вставьте следующий вызов перед запуском пакета SDK:
Убедитесь, что пакет SDK центра приложений успешно настроен, отображается в журналах (на уровне журнала сведений ), а затем проверьте, отображаются ли журналы HTTPS-запросов.
Убедитесь, что устройство подключено.
Иногда на портале может потребоваться несколько минут для работы с журналом. Подождите некоторое время, если это так.
Сбои не отображаются на портале
Убедитесь, что модули SDK интегрированы правильно.
Сбои в работе центра приложений пересылают журнал аварийного восстановления только после перезапуска приложения. Кроме того, пакет SDK не пересылает журналы аварийного восстановления, если вы подключены к отладчику. Убедитесь, что отладчик не присоединен к сбою приложения.
Если вы хотите просмотреть журналы, отправляемые на серверную часть, измените уровень ведения журнала на подробный в приложении. Пакет SDK выполнит печать журналов в консоли. Вставьте следующий вызов перед запуском пакета SDK:
Убедитесь, что пакет SDK центра приложений успешно настроен, отображается в журналах (на уровне журнала сведений ), а затем проверьте, отображаются ли журналы HTTPS-запросов.
Не используйте другие библиотеки, предоставляющие функции создания отчетов о сбоях. В приложении может быть интегрирован только один пакет SDK для отчетов о сбоях.
Убедитесь, что устройство подключено.
Иногда на портале может потребоваться несколько минут для работы с журналом. Подождите некоторое время, если это так.
Чтобы проверить, получил ли сервер в центре приложений о сбое, перейдите к разделу потока журнала в службе аналитики. Ваши сбои должны появиться там после отправки.
Предупреждение, запрашивающее у пользователей обновление, не содержит строк, а только ключи для них
Это означает, что элемент не AppCenterDistributeResources.bundle был добавлен в проект. Убедитесь, что файл был удален в проект Xcode и отображается на Copy Bundle Resources этапе сборки целевого приложения. Он должен появиться там, если вы добавили файл с помощью операции перетаскивания – Xcode делает это автоматически. Если файл отсутствует на этапе сборки, добавьте его, чтобы он был скомпилирован в пакет приложения.
Если вы используете Cocoapods, ресурсы автоматически позаботится об этом. Попробуйте переустановить Pod.
В консоли отображаются сообщения, указывающие, что не удалось открыть базу данных.
Распространение и обновление в приложении блокируют автоматические тесты пользовательского интерфейса
Если включены обновления в приложении, они будут блокировать автоматические тесты пользовательского интерфейса. Процесс обновления будет пытаться пройти проверку подлинности в серверной части центра приложений. Рекомендуется не включать распространение центра приложений для целевого объекта тестирования пользовательского интерфейса.
Почему пакет SDK распространяется как «статическая библиотека»
Основные цели разработки пакета SDK для App Center — это минимальное воздействие на приложение с помощью центра приложений, а также наличие модульного пакета SDK. Это приведет к распространению пакета SDK в виде нескольких динамических связанных общих библиотек.
Исторически iOS не поддерживали динамические связанные общие библиотеки, но были добавлены в iOS 8, как описано в этой записи блога с помощью Ландон Белова.
Apple рекомендует оптимизировать запуск приложения, чтобы не более 400 мс в сеансе ввдк. Для достижения этой цели они специально рекомендуют использовать для динамических общих библиотек статические общие библиотеки. Распространение пакета SDK для App Center для iOS в качестве статической связанной библиотеки следует рекомендациям Apple, чтобы обеспечить максимальную производительность и минимальное воздействие на приложение, включающее пакет SDK.
Чтобы получить дополнительные сведения о статически связанных общих библиотеках и динамических связанных общих библиотеках, мы рекомендуем использовать общую документацию по Apple в разделе. Чтобы узнать больше о влиянии динамических связанных библиотек на производительность, прочитайте запись блогахорацек.
Почему двоичные файлы пакета SDK настолько велики? Мне интересует размер моего приложения
двоичные файлы аппцентер распространяются как платформы fat, содержащие срезы для всех архитектур iPhone и для симулятора iPhone. Вот почему, например, аппцентер. Framework составляет 10,5 МБ для загрузки.
чтобы проиллюстрировать это, мы создали пустое приложение цели-C с помощью Xcode 9,2, добавили двоичные файлы центра приложений в приложение и распределенные сборки выпуска на iPhone 7 с iOS 11,3.
Мы выполнили тесты без Bitcode и не использовали тонкое использование приложений. Эти методы можно использовать для уменьшения размера двоичного файла приложения еще больше.
Приведенные ниже числа могут различаться и зависеть от параметров сборки, поэтому следует рассмотреть их в виде грубого указания. С другой стороны, Добавление пакета SDK для App Center в приложение оказывает минимальное влияние на размер двоичного файла приложения.
Используемые модули центра приложений | Размер экспортируемого IPA | Размер установки |
---|---|---|
Нет (пустое приложение) | 24 КБ | 132 КБ |
Аналитика Центра приложений | 120 КБ | 377 КБ |
Сбой в центре приложений | 239 КБ | 705 КБ |
Распространение через Центр приложений | 163 КБ | 528 КБ |
Все модули центра приложений | 314 КБ | 930 КБ |
Защита значения секрета центра приложений
app_secret — Это идентификатор приложения, необходимо узнать, к какому приложению применяется трафик, а также не может использоваться для извлечения или изменения существующих данных. Если ваше app_secret приложение предоставлено, самый большой риск отправит неправильные данные приложению, но это не повлияет на безопасность данных.
Чтобы получить конфиденциальные данные, необходимо предоставить маркерприложения или пользователя, который создается на стороне клиента. Нет способа обеспечить полную безопасность данных на стороне клиента.
Вы можете улучшить безопасность приложения, используя переменную среды, чтобы внедрить секрет приложения в код. Таким образом, секрет не отображается в коде.
Исследуем iOS SDK и используем недокументированные API
Из этой главы, да и из всей этой книги понятно, что самые лакомые куски программирования под iOS включены в публичные фреймворки, но не в SDK. Неофициальная политика Apple насчет этого проста: вы можете всё это использовать, но только на свой страх и риск. Ваш код может сломаться при следующем обновлении прошивки. Вам самим придётся искать компромисс между риском и прибылью.
Дисклеймеры
Краткая инструкция по поиску в SDK
Оставшиеся, если их не более нескольких десятков, можно попытаться скормить гуглу. Случается, что кто-то уже занимался исследованием API, связанных с найденными символами, и в этом случае задача, считай, решена. В более сложных случаях приходится заниматься реверс-инжинерингом, то есть выяснять, как работают найденные функции, как использовать найденных оповещения и тому подобное.
В большинстве случаев, сгенерированного заголовчного файла достаточно: в нем должны быть довольно хорошо описаны иерархии наследования классов, структуры, методы и т.д, чтобы потратив немного времени можно разобраться с API и использовать его в своём предложении.
К сожалению, иногда информации содержащейся в заголовочном файле недостаточно, чтобы заставить код работать, и тогда приходится анализировать ассемблерный код, сгенерированный otool.
Как узнать сигнатуру неизвестной функции?
1. Найти в интернете, как это не банально. Мне довольно часто попадались китайский сайты, были корейский и японский сайты с очень полезной информацией. Обычно самого кода уже достаточно, чтобы понять что происходит и как используется данная функция, данный класс и т.д. Спасибо многословности и выразительности Objective-C!
2. Для многих простых функций, можно попытаться угадать сигнатуру. Внимание, это может быть довольно опасно.
Использование некоторые простые функции, таких как GSEventSetBackLightLevel, самоочевидно.
void GSEventSetBackLightLevel(float level);
Для многих других я использовал следующий трюк (на примере функции SBGetRingerSwitchState):
В результате этих нехитрых действий получается следующая сигнатура:
Кстати, если в названии функции присутствует слово get, то согласно naming conventions Objective-C эта функция должна возвращать значение по ссылке. Это также видно из приведенного примера.
3. Дизассемблирование. На примере все той же SBGetRingerSwitchState. Используем otool:
Из этого кода, используя даже поверхностные знания arm-ассемблера, можно предположить, что функция принимает два аргумента типа «слово» (word)
Выходит, что у функции два аргумента. Идем дальше, в самый конец.
…
00003964 9e04 ldr r6, [sp, #16]
00003966 6836 ldr r6, [r6, #0]
00003968 9903 ldr r1, [sp, #12]
0000396a 600e str r6, [r1, #0]
// примерно соответствует (в терминах языка си): *r1 = r6; т.е. по адресу, хранящемуся в r1 записывается значение из r6;
// Это значит, что функция возвращает значение по ссылке
0000396c 462e mov r6, r5
0000396e 4630 mov r0, r6
// результат выполнения функции помещается в r0
00003970 b012 add sp, #72
00003972 bdf0 pop
…
В сухом остатке получаем:
Продолжая анализировать этот асcемблерный код, уточняем типы и приходим к окончательному варианту:
Разные прошивки и разные устройства: что может сломаться и как это исправить?
Примеры
Пример 1:
Определение положения бокового переключателя вибро (a.k.a. Ring/Silent switch, Mute switch)
Одной из задач, которые стояли передо мной, было определение положения бокового переключателя, который в оригинале называется ring/silent switch. Этот переключатель используется для переключения между «тихим» и обычном/«громким» режимами в айфоне и айпаде. Поиск по StackOverflow дал решение:
Мои дальнейшие поиски по StackOverflow вывели меня на этот пост. В нем описывается библиотечная функция AudioServicesAddSystemSoundCompletion(), чьё нестандартное поведение рассматривалось разработчиками как баг.
Нестандартное поведение заключается в том, что вызов колбэка MyAudioServicesSystemSoundCompletionProc состоится в конце проигрывания звука в обычном режиме, но сразу после вызова AudioServicesPlaySystemSound в «тихом» режиме. Это создает лазейку для определения текущего состояния переключателя. Если, например, длина аудиофайла что мы проигрываем равна 1 с, то разница во времени вызова MyAudioServicesSystemSoundCompletionProc() в «тихом» и громком режиме составляет 1 c. На этом я построил свое второе, асинхронное решение для определения положения бокового переключателя. Вот оно:
Хотя это новое решение и было рабочим, оно не устраивало меня по нескольким причинам. Во-первых, оно было асинхронным и работало с ощутимой задержкой (около 1/10 секунды). Снижение задержки вело к ложным срабатываниям. Во-вторых, был побочный эффект — сам проигрываемый звук, который звучал достаточно громко чтобы смутить пользователя. Позже я искусственно выкрутил громкость в ноль в аудиоредакторе. В-третьих, это был уже слишком похоже на грязный хак, хотя это, например, не помешало создателям VSSilentSwitch продавать свое решение, по всей видимости основанное на том же эффекте.
Примерно через месяц я вернулся к этой проблеме. Я начал использовать команду nm для поиска символов в объектных файлах, на её основе я написал простейший shell-скрипт, листинг которого можно найти ниже (В разделе «Инструменты»). Скрипт запускается с одним, двумя или тремя параметрами, каждый из которых представляет ключевое слово.
Функция с названием SBGetRingerSwitchState выглядела многообещающе.
Для получения нужного порта использовалась функция:
из того же фреймворка.
Вот что получилось в итоге:
Пример 2:
IMEI (International Mobile Equipment Identity) — уникальный идентификационный
код, присваиваемый каждому телефону, своего рода MAC-адрес телефона (хотя MAC-адрес у телефона также есть)
Я уже и не помню, как я вышел проект Эрики Садун uidevice-extension, но по мере того, как я с ним разбирался он всё больше казался мне этакой программистской «золотой жилой».
Одна из категорий, UIDeviсe(IOKit_Extensions) содержит функции для определения IMEI. Я протестировал эти функции на iPhone 4 c iOS 5.1 и iPad c iOS 4.3, всё работало и я перешел к другим задачам. Но в ходе бета-тестирования выяснилось, что функция для определения IMEI не работает на новых устройствах: iPad 2, the new iPad и iPhone 4S. Для выяснения причин я отправился на StackOverflow, где мои опасения подтвердились. Поиски привели меня тогда к фреймворку под названием CoreTelephony.
Можно предположить что функция (_CTServerConnectionCopyMobileEquipmentInfo(. )) возвращает словарь(CFDictionaryRef) c ключами вида kCTMobileEquipmentInfo* и соответствующими им значениями. К счастью, на этот раз мне не пришлось восстанавливать сигнатуру. Поиск в гугле по запросу _CTServerConnectionCopyMobileEquipmentInfo привел меня на эту страничку, и вскоре функция для определения IMEI была готова.
Этот метод определения IMEI работает на всех устройствах.
Позже я нашел еще один метод определения IMEI (через lockdownd).
Пример 3:
Использование недокументированных оповещений: нажатия кнопок громкости.
Изначально я наивно полагал, что любая символьная константа, заканчивающаяся на «Notification» является названием системного оповещения и её можно использовать, просто зарегистрировав наблюдателя (observer) с помощью [NSNotificationCenter defaultCenter].
Написав тестовую программу, я принялся проверять, какие оповещения приходили в ответ на нажатия клавиш громкости.
Из составленного мной довольно большого списка опопвещений приходили только вот эти 2:
Недостаток этих оповещений в том, что
1) Нельзя напрямую определить, какая из двух кнопок была нажата
2) Нельзя отследить, когда нажата и когда отпущена каждая из кнопок
Ищу по другим ключевым словам:
Четыре оповещения из UIKit сработали не сразу: необходимо было подать связанную с ними команду.
После этого стали приходить оповещения о нажатиях соответствующих кнопок.
Побочный эффект: вызов данной функции приводит к тому, что кнопки громкости больше не регулируют громкость, так что по завершении работы с кнопками следует вызвать
Пример 4:
Использование недокументированных оповещений: отслеживание статуса SIM-карты
Работаем по проверенной схеме:
Наиболее подходящими мне показались оповещения под названиями:
1) kCTSIMSupportSIMInsertionNotification
2) kCTSIMSupportSIMStatusChangeNotification
3) kCTSIMSupportSIMTrayStatusNotification
Простейшая тестовая программа показала, что оповещения под названием (1) приходили только в момент вставки сим-карты (я мог бы догадаться и раньше по названию), (2) приходили именно тогда когда мне нужно (при вставке и вынимании), оповещения (3) не приходили вообще. Позже я узнал, что оповещения (3) относятся к специальному центру оповещений под названием CTTelephonyCenter. Об использовании CTTelephonyCenter можно прочитать здесь.