- MalformedURLException: unknown protocol: android
- android.os.DeadSystemException crash on Samsung devices #1053
- Comments
- anitaa1990 commented May 8, 2019 •
- anitaa1990 commented May 8, 2019
- anitaa1990 commented May 8, 2019
- AmandaRiu commented May 17, 2019
- sentry-io bot commented Mar 25, 2020
- shiki commented May 4, 2020
- AmandaRiu commented May 18, 2020
- AmandaRiu commented May 18, 2020
- sentry-io bot commented May 20, 2020
- sentry-io bot commented May 20, 2020
- sentry-io bot commented Oct 26, 2020 •
- nbradbury commented Nov 17, 2020
- fzyzcjy commented Mar 28, 2021
- nbradbury commented Apr 5, 2021
- fzyzcjy commented Apr 5, 2021
- How to identify what is accessing hidden methods
- 1 Answer 1
- Update: The SQLite methods
- Crash on start: Non-browser selected #89
- Comments
- andreban commented Apr 26, 2020
- andreban commented Apr 26, 2020 •
- andreban commented Apr 27, 2020
- AlexBorsody commented May 13, 2020 •
- AlexBorsody commented May 13, 2020 •
- dazbradbury commented May 14, 2020
- andreban commented May 14, 2020
- dazbradbury commented May 14, 2020
- AlexBorsody commented May 14, 2020
- andreban commented May 14, 2020
- dazbradbury commented May 15, 2020
- andreban commented May 15, 2020
- dazbradbury commented May 27, 2020
- Свежий взгляд на отображение диалогов в Android
- Решение «в лоб»
- Устаревший способ
- Способ из документации
- Поиск идеального решения
- Реактивный способ
- Пишите диалоги правильно
MalformedURLException: unknown protocol: android
I was trying to adapt the code from this: 3D-model-viewer to my app because I want to insert some models from that kind to show human anatomy.
Everything seems fine, I first cloned and tried the original repository, it worked, so I started using that code.
After adapting and checking everything’s okay and there are no errors marked, I ran the app, but there seems to be an issue. In the original code, the person saves a url like this:
I already changed the first part to my project:
so I don’t think is that, algo I inserted some logs to verify the params aren’t null.
The class in github is here: SceneLoader.java
So, when I get to that point, the Logcat says «unkown protocol: andorid». Here’s the complete logcat:
My repository is this, the app runs, there are no errors marked, just when selecting the 3rd option in my menu (it’s the first screen) it crashes.
I kept the url line like that since I didn’t know if the «android://» part was really important or not.
What do you think I should change or do you know what that error means? Do I need to import anything? I checked the original project (manifest, folder structure, gradle) and everything is similar, so I don’t know where the mistake lies.
At the end, what I want is to access my assets folder to show some .obj files. And for the URL, I know that for links you should put a protocol, but I don’t get why the protocol android isn’t working for getting something in one of my project paths.
EDIT: In my repository I made some changes to get the obj file, still, if someone could tell me (as the modification hadn’t anything to do with the url) how to manage that about the android protocol. I checked this link: URL but I couldn’t find much.
Источник
android.os.DeadSystemException crash on Samsung devices #1053
Comments
anitaa1990 commented May 8, 2019 •
Not a very helpful stacktrace:
Affected users: 2 across 2 crash reports
Fabric: 5c88c55af8b88c2963ec6ed7 5c63d165f8b88c2963a658b9
App Version: 1.7-rc-1 (51), 1.6
Device: Samsung Galaxy Note 8 and 9 (OS version: 9.0)
Similar issues: #920
The text was updated successfully, but these errors were encountered:
anitaa1990 commented May 8, 2019
Update: Seeing similar issues here for Samsung devices alone.
anitaa1990 commented May 8, 2019
Since we are catching the exception and ignoring it here not sure where the issue is happening.
Tried replicating the issue with Genymotion but no luck so adding Mystery label to it and putting it in the back burner for now.
AmandaRiu commented May 17, 2019
An interesting thing to note is that this is only happening on Samsung devices, and only once per user. In this SO article (also posted above), they note that it also seems to only happen on devices upgrading from Android 8 to 9.
sentry-io bot commented Mar 25, 2020
shiki commented May 4, 2020
As of May 4, 2020:
- 186 events
- Affected 60 users
AmandaRiu commented May 18, 2020
As of May 18, 2020:
- 205 events
- Affected 62 users
AmandaRiu commented May 18, 2020
So far no answer.
sentry-io bot commented May 20, 2020
sentry-io bot commented May 20, 2020
sentry-io bot commented Oct 26, 2020 •
This crash looks interesting. It has more details to the DeadOsException crash.
Seems like it might have something to do with not being able to stop NotificationsProcessingService .
nbradbury commented Nov 17, 2020
As of Nov 17, 2020: 447 Events, 34 Users.
It’s happening on mainly Samsung devices, with a few others. This Medium article suggests is due to notification bug in Oreo related to setting the vibration pattern of a notification, but we don’t use that feature, and we’re seeing it on a variety of Android versions.
I’m tempted to simply close this issue because the docs on DeadSystemException state «The core Android system has died and is going through a runtime restart. All running apps will be promptly killed,» and that doesn’t seem like anything we can resolve.
fzyzcjy commented Mar 28, 2021
Hi did you solve the problem? I also see this problem on my application. Though not the same app, IMHO the cause may be similar.
nbradbury commented Apr 5, 2021
I’ve marked this issue as ignored in Sentry since it’s not a problem with our code. The device is simply restarting, which kills all running processes, and if any of those processes tries to access the system at this point they’ll cause this exception.
fzyzcjy commented Apr 5, 2021
@nbradbury Thank you very much!
You can’t perform that action at this time.
You signed in with another tab or window. Reload to refresh your session. You signed out in another tab or window. Reload to refresh your session.
Источник
How to identify what is accessing hidden methods
I have a flutter app that generates a lot of hidden API warnings:
And so on. I haven’t written any code to use Android’s SQLiteDatabase or AccessibilityNodeInfo , but this doesn’t provide any information about which bit of code is calling these hidden methods. It could be in Flutter, or one of the several plugins I have. Short of mutilating my code to remove these plugins, is there anything I can do to find out what code is calling these? I.e. to get a stack trace.
Does Android have an option to crash on hidden field accesses rather than just logging them, or something similar?
1 Answer 1
Aha, thanks to Mark Keen’s link, I was able to create a custom Application for my Flutter app that logs the stack track for strict mode violations. Create a MainApplication.kt Kotlin file like this:
And then point your AndroidManifest.xml to it:
Then when you run it you should see a stack trace. In this case the AccessibilityNodeInfo stuff does appear to be a Flutter issue:
Update: The SQLite methods
Weirdly, it still didn’t print any stack traces for the SQLite errors, but I noticed that the first errors were for «reflection» whereas those were for «linking». I am linking with a Rust library that uses a bundled copy of SQLite — using this dependency:
And then loading it in Dart:
When I commented that line out and ran wgradle clean (necessary it seems), the errors went away! Wtf? It seems like Android intercepts dlopen() and checks if you link against any of the forbidden symbols.
But the really weird thing is that my libmap_render.so doesn’t link with SQLite (because it’s statically linked into it):
I also couldn’t find any SQLite symbols in the symbol table, relocations, etc. So I have literally no idea what Android is doing. Does it literally scan the binary?
Источник
Crash on start: Non-browser selected #89
Comments
andreban commented Apr 26, 2020
Describe the bug
While the default system browser (where any link opens by default) is set to an actual browser (Brave, also tried setting to Chrome), for some reason an app that is not a browser and does not appear in the system browser selection (Revolut) is selected as TWA provider which causes a crash on start.
To Reproduce
Launching the app on my phone in debug mode returns these logs before the app crashes:
Expected behavior
The app should not crash
Smartphone (please complete the following information):
- Device: SM-G950F
- OS: Android 9 on newest patch (April 1 2020)
- Browser: Brave Browser
The text was updated successfully, but these errors were encountered:
andreban commented Apr 26, 2020 •
The library retrieves a list of browsers from PackageManager to check applications that can handle the following Intent:
It seems com.revolut.revolut is returned by the PackageManager (unexpected), but doesn’t handle https://travelfeed.io/?utm_source=pwa (expected). I’ll take a look at how com.revolut.revolut is configured to understand why it’s being returned by the PackageManager.
andreban commented Apr 27, 2020
I reproduced this by uninstalling / disabling all browsers on the device, installing Revolut and opening a Trusted Web Activity. I get the same stacktrace on logcat.
The intent-filter that seems to be matching the query in Revolut’s APK is the following:
I’m not sure what @string/0x2f matches in their APK yet.
AlexBorsody commented May 13, 2020 •
I am seeing a similar issue using the TWA repository to submit my app to the Play Store. It only happens to a small percent of our users I can tell from the crash report as our app is live. There really isn’t much custom here I used the TWA repo to wrap my website that’s it.
AlexBorsody commented May 13, 2020 •
The issue started showing up in the crash logs April 19th even though nothing was updated on our side. Thanks so much for your help.
dazbradbury commented May 14, 2020
Also started to get this same error on the 16th April, and it is still ongoing:
This error seems similar to one when we first created our TWA, but google released an updated custom tabs version to rectify the error. So to be explicit, our implementation is set to:
andreban commented May 14, 2020
Also started to get this same error on the 16th April, and it is still ongoing:
This error seems similar to one when we first created our TWA, but google released an updated custom tabs version to rectify the error. So to be explicit, our implementation is set to:
@dazbradbury a bit unrelated to this issue, but the recommended way of using Trusted Web Activity is via android-browser-helper currently: https://developers.google.com/web/android/trusted-web-activity/android-browser-helper-migration
dazbradbury commented May 14, 2020
@andreban Thanks — happy to update now. Would I be able to tell users this will fix the issue we’re seeing, or is this issue present in both the latest and old versions of how the TWA libraries are accessed?
AlexBorsody commented May 14, 2020
Sounds like it’s unrelated from the way he phrased it. But please update us if it by any chance fixes the issue.
andreban commented May 14, 2020
For this particular error, unlikely — But there are other issues fixed in the new library, and many other features.
This comment #89 (comment) describes what I could understand from the issue — It’s about PackageManager returning an app that doesn’t actually handle the URL we’re trying to launch. So, when we actually try to launch we get an ActvityNotFoundException . The logic for picking the provider is here.
In the case of TrustedWebActivity, we know the URL that’s going to be launched beforehand. I’m wondering if it’s worth running the PackageManager against startUrl — This may return the app itself as a handler, but we know the package and can ignore it.
dazbradbury commented May 15, 2020
Just to confirm — having updated the app, we’re still seeing exceptions on the latest version:
`java.lang.RuntimeException` —> `Caused by: android.content.ActivityNotFoundException: `
Seems to be effecting new devices. Let me know if I can provide any more insight / examples, otherwise thanks for the work and look forward to a fix!
andreban commented May 15, 2020
Can you reproduce on a dev device? I’d be interested to know if there’s another app other than com.revolut.revolut causing the issue.
dazbradbury commented May 27, 2020
I’ve not been able to reproduce. I can see that we’ve had 322 reports in the last 7 days (not huge, but not insignificant).
If I simply install Revolut on a device, and try opening a TWA, I don’t get the issue. I’m not sure if having a Revolut account would make a difference, but if it does, I only tested with the app installed (no account logged into).
Источник
Свежий взгляд на отображение диалогов в Android
На картинке первая мысль читателя, который недоумевает, что можно написать про такую простую задачу как отображения диалога. Аналогично думает и менеджер: «Тут ничего сложного, наш Вася за 5 минут сделает». Я, конечно, утрирую, но на самом деле всё не так просто, как кажется на первый взгляд. Особенно если мы говорим про Android.
Итак, на дворе шёл 2019 год, а мы всё ещё не умеем нормально показывать диалоги.
Давайте всё по порядку, и начнем с постановки задачи:
Требуется показать простой диалог с текстом для подтверждения действия и кнопками «подтвердить/отмена». По нажатию на кнопку «подтвердить» — совершить действие, по кнопке «отмена» — закрыть диалог.
Решение «в лоб»
Я бы назвал этот способ джуниорским, потому что не первый раз сталкиваюсь с непониманием, почему нельзя просто использовать AlertDialog, как показано ниже:
Довольно распространенный способ для начинающего разработчика, он очевиден и интуитивно понятен. Но, как и во многих случаях при работе с Android, этот способ совершенно неправильный. На ровном месте мы получаем утечку памяти, достаточно повернуть устройство, и вы увидете в логах такую ошибку:
На Stackoverflow вопрос по этой проблеме один из самых популярных. Если коротко, то проблема в том, что мы либо показываем диалог, либо не закрываем диалог после завершения работы активити.
Можно, конечно, вызывать dismiss у диалога в onPause или onDestroy активити, как советуют в ответе по ссылке. Но это не совсем то, что нам нужно. Мы хотим, чтобы диалог восстанавливался после поворота устройства.
Устаревший способ
До появления фрагментов в Android диалоги должны были отображаться через вызов метода активити showDialog. В этом случае активити правильно управляет жизненным циклом диалога и восстанавливает его после поворота. Создание самого диалога нужно было реализовать в коллбэке onCreateDialog:
Не очень удобно, что приходится заводить идентификатор диалога и передавать параметры через Bundle. И мы все ещё можем получить проблему «leaked window», если попытаемся отобразить диалог после вызова onDestroy у активити. Такое возможно, например, при попытке показать ошибку после асинхронной операции.
Вообще, эта проблема типична для Android, когда нужно что-то сделать после асинхронной операции, а активити или фрагмент уже уничтожен в этот момент. Наверное, поэтому MV*-паттерны более популярны в Android-сообществе, чем среди iOS-разработчиков.
Способ из документации
В Android Honeycomb появились фрагменты, и описанный выше способ устарел, а метод showDialog у активити помечен как deprecated. Нет, AlertDialog не устарел, как ошибаются многие. Просто теперь появился DialogFragment, который оборачивает объект диалога и управляет его жизненным циклом.
Родные фрагменты тоже устарели начиная с 28 API. Теперь следует использовать только реализацию из Support Library(AndroidX).
Давайте реализуем нашу задачу, как это предписывает официальная документация:
- Для начала нужно наследоваться от DialogFragment и реализовать создание диалога в методе onCreateDialog.
- Описать интерфейс событий диалога и инстанцировать слушатель в методе onAttach.
- Реализовать интерфейс событий диалога в активити или фрагменте.
Если читателю не очень понятно, почему нельзя передавать слушатель через конструктор, то он может почитать подробнее об этом тут
Код фрагмента диалога:
Достаточно много кода получилось, не так ли?
Как правило, в проекте есть какой-нибудь MVP, но я решил, что вызовы презентера можно опустить в данном случае. В примере выше стоит ещё добавить статический метод создания диалога newInstance и передачу параметров в аргументы фрагмента, всё как полагается.
И это всё ради того, чтобы диалог вовремя скрывался и правильно восстанавливался. Не удивительно, что появляются такие вопросы на Stackoverflow: один и два.
Поиск идеального решения
Текущее положение дел нас не устраивало, и мы стали искать способ, как сделать работу с диалогами более комфортной. Было ощущение, что можно сделать проще, почти как в первом способе.
Ниже сформулированы соображения, которыми мы руководствовались:
- Нужно ли сохранять и восстанавливать диалог после убийства процесса приложения?
В большинстве случаев это не требуется, как и в нашем примере, когда нужно показать простое сообщение или что-то спросить. Такой диалог актуален пока не потеряно внимание пользователя. Если его восстановить после долгого отсутствия в приложении, то пользователь потеряет контекст с планируемым действием. Поэтому нужно только поддержать повороты устройства и правильно обрабатывать жизненный цикл диалога. Иначе от неловкого движения устройства пользователь может потерять только что открытое сообщение, не прочитав его. - При использовании DialogFragment появляется слишком много boilerplate-кода, теряется простота. Поэтому было бы неплохо избавиться от фрагмента как обёртки и использовать Dialog напрямую. Для этого придется хранить состояние диалога, чтобы показать его вновь после пересоздания View и скрывать, когда View умирает.
- Все привыкли воспринимать показ диалога как команду, особенно если работаешь только с MVP. Задачу последующего восстановление состояния берет на себя FragmentManager. Но можно посмотреть на эту ситуацию иначе и начать воспринимать диалог как state. Это намного удобнее при работе с паттернами PM или MVVM.
- Учитывая, что большинство приложений сейчас используют реактивные подходы, появляется потребность в том, чтобы диалоги были реактивными. Основная задача — не разрывать цепочку, которая инициирует показ диалога, и привязать реактивный поток событий для получения результата от него. Это очень удобно на стороне PresentationModel/ViewModel, когда манипулируешь несколькими потоками данных.
Мы учли все вышеописанные требования и придумали способ реактивного показа диалогов, который успешно реализовали в нашей библиотеке RxPM (про нее есть отдельная статья).
Само решение не требует библиотеки и может быть сделано отдельно. Руководствуясь идеей «диалог как state» можно попробовать построить решение на основе модных ViewModel и LiveData. Но я оставлю это право за читателем, а далее речь пойдет уже о готовом решении из библиотеки.
Реактивный способ
Я покажу, как исходная задача решается в RxPM, но сначала пару слов о ключевых понятиях из библиотеки:
- PresentationModel — хранит реактивный стейт, содержит UI-логику, переживает повороты.
- State — реактивный стейт. Можно воспринимать как обертку над BehaviorRelay.
- Action — обертка над PublishRelay, служит для передачи событий от View в PresentationModel.
- State и Action имеют observable и consumer.
За состояние диалога отвечает класс DialogControl. Он имеет два параметра: первый для типа данных, которые должны отображаться в диалоге, второй — для типа результата. В нашем примере тип данных будет Unit, но это может быть сообщение пользователю или любой другой тип.
В DialogControl есть следующие методы:
- show(data: T) — просто отдает команду на отображение.
- showForResult(data: T): Maybe — показывает диалог и открывает поток для получения результата.
- sendResult(result: R) — отправляет результат, вызывается со стороны View.
- dismiss() — просто скрывает диалог.
В DialogControl хранится состояние — есть диалог на экране или нет (Displayed/Absent). Вот так это выглядит в коде класса:
Создадим простую PresentationModel:
Обратите внимание, что обработка кликов, получение подтверждения и обработка действия реализованы в одной цепочке. Это позволяет сделать код сфокусированным и не раскидывать логику по нескольким коллбэкам.
Далее просто привязываем DialogControl во View с помощью экстеншена bindTo.
Собираем обычный AlertDialog, а результат отправляем через sendResult:
При типичном сценарии под капотом происходит примерно следующее:
- Кликаем на кнопку, событие через Action «buttonClicks» попадает в PresentationModel.
- По этому событию запускаем отображение диалога через вызов showForResult.
- В результате состояние в DialogControl меняется с Absent на Displayed.
- При получении события Displayed — вызывается лямбда, которую мы передали в привязке bindTo. В ней создается объект диалога, который затем показывается.
- Пользователь нажимает, кнопку «Confirm», срабатывает слушатель и результат нажатия отправляется в DialogControl посредством вызова sendResult.
- Далее результат попадает во внутренний Action «result», а состояние с Displayed меняется на Absent.
- При получении события Absent текущий диалог закрывается.
- Событие от Action «result» попадает в поток, который был открыт вызовом showForResult и обрабатывается цепочкой в PresentationModel.
Стоит отметить, что диалог закрывается и в момент, когда View отвязывается от PresentationModel. В этом случае состояние остается Displayed. Оно будет получено при следующей привязке и диалог будет восстановлен.
Как видите, необходимость в DialogFragment пропала. Диалог показывается, когда View привязывается к PresentationModel и скрывается, когда View отвязывается. За счёт того, что состояние хранится в DialogControl, который в свою очередь хранится в PresentationModel, диалог восстанавливается после поворота устройства.
Пишите диалоги правильно
Мы с вами рассмотрели несколько способов отображения диалогов. Если вы все ещё показываете первым способом, то прошу вас, не делайте больше так. Для любителей MVP ничего не остается, как использовать стандартный способ, который описан в официальной документации. К сожалению, склонность к императивности этого паттерна не позволяет сделать по-другому. Ну, а фанатам RxJava рекомендую присмотреться к реактивному способу и нашей библиотеке RxPM.
Источник