Как стать автором
Обновить

Комментарии 21

Как-то раз разрабатывал приложение с помощью ionic, а после этого (уже другое) пересел на native. Косяков и здесь и там хватает, однако такой ад может быть только в native. Для меня странно вручную заниматься обработкой кнопок диалогов, передачей объектов между стейтами, императивным выставлением бекграундов для сообщений. А уж вся эта заваруха с адаптерами и спиннерами, охох...
Недавно назначил один и тот же Drawable фоном двум View — потом не мог понять, почему у одной из View фон «обрезан» — оказалось, всё дело в общих bounds; помог getConstantState().newDrawable(). ДЛя меня разработка для Android — хождение по полю, усеянному невидимыми граблями разной длины; и хорошо, если ударит в грудь. RTFM здесь обязателен, хотя и здесь не без чудес: зачастую документация по методу doSomething() ограничивается фразой «Does something», описания аргументов и возвращаемых значений порой отсутствует или врёт, иногда у метода вообще нет описания.

Весь SDK написан в нескольких разных стилях, кое-где авторы не знают про существование generics, классы часто сложно или невозможно расширять за пределами простейших вещей типа перехвата прокрутки. Относительно мало готовых компонентов, часто SDK тебе даёт бревно и перочиный ножик, а бруски для стула ты должен делать сам. Как-то понадобилось сделать редактор rich text с вложенными цитатами и блоками кода — оказалось, нет даже какого-нибудь базового RichEditText пришлось кастовать причудливые заклинания со Spannable.

В общем, на слова «разработка для Android» у меня первая ассоциация — «геморрой». Радует только наличие качественной IDE, за которую спасибо в первую очередь JetBrains, и интегрированный в неё Android Lint.
Самый глубокий кювет для меня был при работе с arm64 девайсом и нативными либами.
Несмотря на то, что все arm64 девайсы могут без проблем юзать arm-v7 либы, приложение крашилось, т.к. по какой-то причине искало именно x64 версию одной библиотеки.
После 3 дней курения проблемы, оказалось, что если у вас в проекте есть хоть одна нативная либа собранная для х64, то все остальные нативные библиотеки андроид тоже начинает искать в папке для х64, и победить это нельзя вообще никак, только если заменить все на х64, либо все на arm-v7.
Прийти к решению было очень непросто, так как напрямую мы подключали только одну нативную библиотеку, о остальные просто втихую использовались какими-то другими зависимостями.
Так и не нашел где такое поведение задокументировано...
Блин. Я даже не знаю — смеяться или плакать. А в какой документации вы прочитали, что солнце восходит на западе, а заходит на востоке? Где прописано что рыбы плавают, а птицы летают?
Это ж до какой степень нужно не понимать как в принципе операционки устроены чтобы ожидать, что вы сможете в один процесс грузить и arm64 и arm-v7 либу?
Не то, что это относится к категории "это в принципе невозможно". Возможно. В программирование вообще мало невозможного. Есть трюки, позволяющие это сделать на некоторых системах (нет, не на arm64, но на x86 — nspluginwrapper и всё такое), но как сказал один мой знакомый: «говорить о том, что надёжность у этих трюков "как у чего-то скрепленного скотчем или проволокой" — это оскорблять надёжные, проверенные строительные инструменты».
Ни Windows, ни GNU/Linux, ни MacOS, ни вообще какая-бы-то-ни-была известная операционка ничего такого по умолчанию не позволяет и позволять никогда не будет — почему Android должен быть исключением? Потому что у него "главная программа" — это не нативный бинарник, а Java-класс? А почему это должно как-то влиять на нативный код?
Тише, тише.
Как я уже сказал, в проекте напрямую не было видно, что используются какие-то другие нативные библиотеки.
О том, что какая-то из подключаемых в Gradle библиотек имеет внутри скомпиленную под arm64 .so'шку, можно было только догадываться.
К тому же, нет возможности указать какую либу использовать, arm64 или arm-v7. По-моему в ситуации, когда есть 5 либ под v7 и одна под x64 (которая в том числе есть и под v7), было бы логичнее сделать fallback на v7, а не пытаться все 5 найти под v7 и не давать возможности изменить это поведение.
Так что давайте не будем тут про понимание устройства ОС.
пардон,
а не пытаться все 5 найти под x64*
А сколько и каких либ грузится под x64 — это уже ваше приложение решать будет. Хочет — загрузит одну, хочет — все пять. Хозяин — барин.
По-моему в ситуации, когда есть 5 либ под v7 и одна под x64 (которая в том числе есть и под v7), было бы логичнее сделать fallback на v7, а не пытаться все 5 найти под v7 и не давать возможности изменить это поведение.
Это с какого-такого перепугу? Вы включили в APK'шку arm64-v8a библиотеку и, тем самым, сказали Android'у: да, архитектура arm64-v8a мною поддерживается. А что вместо 5 либ у вас теперь одна — ну так кто ж вам судья? Может те 4 либы раньше реализовывали логику, которая сейчас просто не нужна (ну там эмутяцию петабайтных массивов в стиле EMS или еще чего).
Никто и никогда не принимает решение «грузить arm64 либу» или «грузить arm-v7 либу».
Принимается решение: запускать 32-битный процесс или 64-битный процесс. Всё остальное — следует уже из этого решения. Какая виртуальная машина запускается, сколько памяти выделается и т.д. и т.п. Вы можете вообще никакую нативную библиотеку никогда не грузить — но, тем не менее, получить ограничение в 4GiB памяти на процесс если у вас файлики в arm-v7 каталоге лежат.
P.S. Скаживе спасибо, что Android — не iOS. Там эта проблема решена ещё проще: если есть arm-v7 либа, то должна быть и arm-v8 либа, иначе вам опубликовать приложение просто не дадут :-)
Кстати насчёт документации.
Сейчас пошёл, проверил — всё подробно описано там, где, собственно, и должно быть описано: в разделе «Android Platform ABI support» подробно описано — как и когда выбираются библиотки, следующий раздел «Automatic extraction of native code at install time» подробно объясняет — как и куда они копируются при установке.
Так что это поведение и логично и подробно описано — не знаю на что у вас ушли три дня...
Хорошо, по-вашему логично, что у меня есть в проекте arm-v7 библиотека, а Android пытается найти ее х64 версию.
Что бывает очевиднее. И да, это поведение там конкретно не описано.
When installing an application, the package manager service scans the APK, and looks for any shared libraries of the form:
lib/<primary-abi>/lib.so
If none is found, and you have defined a secondary ABI, the service scans for shared libraries of the form:
lib/<secondary-abi>/lib.so
Вот у меня есть secondary ABI, но Android искал только primary.
Вот у меня есть secondary ABI, но Android искал только primary.
Недосточно того, чтобы был «secondary-abi». Нужно ещё чтобы «primary-abi» отсутствовал как класс (if none is found and… ). Если у вас так было — файлите баг.
64 битный процесс не может использовать 32 битные .so(.dll). Это справедливо для всех операционных систем, не только андроида. Если в вашем приложении есть хотя-бы одна 64 битная библиотека то система запустит ваше приложение в 64 битном режиме. А определить каких библиотек не хватает, не запуская приложение, сложная задача. Единственное решение которое приходит в голову, это добавить warning в lint что у вас разное количество библиотек на разные архиткетуры. Хотя в некоторых проектах это будет ложным срабатыванием.
Можно составить список native экспортов в Java коде и сопоставить с собранными бинарниками, а также проверить, чтобы сами бинарники не потеряли зависимостей (а-ля ldd). Но кто же это писать то будет...
Никто не будет потому что это бред. Наличие неразрешённых экспортов в Java коде само по себе ошибкой не является (представьте что у вас есть несколько классов, который, блин, реализуют петабайтные массивы на 32-битной платформе в стиле EMS… на 64-битной платформе они перестанут быть нужны). А вот наличие библиотек, которые нельзя использовать — ошибкой является. Зачем они в вашей .APK'шке если вы никогда и ни при каких условиях не собираетесь их использовать?
Потретить кучу времени и сил для того, чтобы кому-то поломать правильно написанную программу — сомнительное удовольствие.
Добавление хитрых эвристик в подобные места — плохая затея. Так иногда делают, чтобы "обойти конкурета на повороте" — но это не делает затею менее плохой. Пример — Internet Explorer и его "гениальная" идея о том, что нужно угадывать тип файла если вебмастер идиот и неправильно настроил web-сервер. Помогло в своё время отыграть пару процентов рынка, но в результате теперь все создатели веб-браузеров и все web-разработчики вынуждены это учитывать. Первые — должны реализовывать довольно-таки сложный алгоритм и писать кучу тестов на него. Вторые — должны о нём не забывать и/или постоянно затыкать возникающие из-за него бреши в безопасности. Причём — это уже навсегда.
Причём я уверяю вас: они всё равно рано или поздно дадут сбой. И если Dimezis потратил три дня на борьбу с простым и задокументированных подходом, то сбой в сложной программе "вынюхивания" он бы занёс в категорию "злые божества сломали мою программу и починить её теперь нельзя никак, она теперь использовать amd64 не сможет никогда".
Не надо так делать.
Если глянуть в документацию, то сразу видно, что getFragmentManager() для фрагмента возвращает… FragmentManager родительского активити (не родителя, а именно активити!).
Вообще-то в документации сказано:
If this Fragment is a child of another Fragment, the FragmentManager returned here will be the parent's getChildFragmentManager().
Т.е. для вложенных фрагментов возвращается getChildFragmentManager родительского фрагмента.
developer.android.com/intl/ru/reference/android/app/Fragment.html#getFragmentManager%28%29
Вы правы. Почему-то помнилось, что оно возвращает именно менджер активити. Исправил.
Стиль изложения шикарен — и весело, и без воды.
На фразе «А ничего. Живи с этим» подавился чаем :)
Плюсовать нечем, но в избранное добавил.
Реквестирую обе анонсированные части — ради таких статей собственно и читаю хабр.
Жду продолжения.
А я пытаюсь запилить облегченный фреймворк, базирующийся на нативных WebView, в отличии от того же PhoneGap или Crosswalk. Так я с определением открыта ли софтверная клавиатура, сначала намучился. Но в итоге сделал гибрид через onclick/onblur на html input и onMeasure на лайоте, на котором развернулся WebView.

Плюс еще залез в сам WebView и переопределил onSizeChanged, чтобы уведомлять веб-приложение о новых размерах окна WebView и наличия на экране софтверной клавиаутры.

И конечно переопределил onConfigurationChanged, чтобы WebView не создавался заново при смене ориентации.

В итоге, у меня WebView крешится. Если открыть софтверную клавиатура, а после начать менять ориентацию устройства, то может уже на 2-3 раз смены ориентации отвалиться. А может после 10 раза ) Правда у меня девайс очень старый на 4.0.3, вот жду Xiaomi на 5.1, может хоть там такого бага не будет. А вот в эмуляторах на всех версиях работает без крешей.
Вопрос не в версии устройства. На "очень старых девайсах" может памяти не хватать. Клавиатуру убъют и пересоздатут — а вы этого не заметите. На Galaxy Nexus поэтому очень сложно пользоваться Chrome'ом: ввод чего-либо превращается в ад. Любое действие (ну там сообщение от GMail'а что почта пришла) нарушает хрупкий баланс и клавиатура убирается. После пары тапов — возвращается и можно ввести ещё пару букв...
Зарегистрируйтесь на Хабре, чтобы оставить комментарий

Публикации