Ostatnio na slacku w kanele poświęconym Androidowi padło pytanie, w jaki sposób wyświetlić naszą aplikację na liście 'Odtwórz za pomocą”. Dziś właśnie tym problemem chciałbym się zająć.
Czym jest Deep Links i jak to działa?
Najprościej wytłumaczyć to na przykładzie. Mamy taką sytuację, przeglądasz pliki przy pomocy menadżera plików np.: Total Comandera lub stockowego menadżera i chcesz odtworzyć plik z rozszerzeniem txt, pdf. Po kliknięciu dostajesz listę aplikacji, które obsługują dany format. Jeżeli jest tylko jedna aplikacja, to z automatu otwiera daną aplikację. Również może się zdarzyć, że mamy ustawioną aplikację jako domyślną do otwierania danego rozszczelnienia. Jeżeli zdarzy się, że mamy kilka aplikacji w systemie, które obsługują dany format lub nie mamy ustawionej domyślnej aplikacji, dostaniemy listę z aplikacjami, za pomocą których możemy wyświetlić plik.
Deep Links, czyli głębokie połączenia to nic innego jak jakiś link, który jest głęboko powiązany z jedną z zainstalowanych aplikacji.
Wszystkie poniższe przykłady zostały przetestowane na telefonie Honor 8 z Androidem 7.1. Zachowania aplikacji mogą się różnić w zależności od urządzenia, modelu telefonu itp.
Chce taki bajer!
Cała filozofia opiera się na pliku AndroidManifest.xml. Poniżej masz przedstawiony kod, który możesz znaleźć w internecie i teoretycznie powinien działać:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:host="*" android:mimeType="*/*" android:pathPattern=".*\\.txt" android:scheme="file" /> </intent-filter>
Taki kod wstawiamy między znacznikami <activity>. Nie wstawiamy go między <service> i <receiver>!
Jeżeli teraz wejdziemy w aplikację TC, to zobaczymy, że nasza aplikacja jest:
Natomiast, gdy wejdziemy w menadżer plików zainstalowany domyślnie przez producenta, nie zobaczymy naszej aplikacji 🙁 Zatem zmodyfikujmy nasz kod na:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <data android:mimeType="text/*" /> </intent-filter>
Teraz działa na jednym i drugim menadżerze plików Jak to możliwe? Spójrz na te dwa ekrany:
Po lewej stronie masz URL pobrany z intenta od total commandera, a po prawej z aplikacji stockowej. Ta różnica wynika z tego, w jaki sposób menadżer plików wysyła Intent i jakie dane do niego przekaże.
Chce więcej przykładów!
W powyższym kodzie aplikacja będzie znajdowała się na liście wszystkich plików, które posiadają typ MIME jako text, ale możemy mieć też inne typy MIME:
<data android:mimeType="image/*" /> <data android:mimeType="application/pdf" /> <data android:mimeType="application/zip" />
Jeżeli chcesz wskazać, które rozszerzenia aplikacja obsługuje, musisz dodać kolejny filtry:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="*" /> <data android:scheme="file" android:host="*" android:pathPattern=".*\.pdf" /> <data android:scheme="file" android:host="*" android:pathPattern=".*\.txt" /> </intent-filter>
Oczywiście nadal na otwieranych plikach tekstowych, np.: .config, pokaże nam się aplikacja. Zauważ ten jedną rzecz, jeżeli dodasz wpis:
<data android:scheme="file" android:host="*" android:pathPattern=".*\.config" />
A nie będzie aplikacji, które obsługuje rozszerzenie .config. W takim przypadku Total Commander włączy od razu naszą aplikację, nie pokaże listy. Z drugiej strony, menadżer plików stockowy pokaże listę. Jeszcze w taki sposób możemy zrobić filtr intencji zamiast powyższego i też zadziała:
<intent-filter> <action android:name="android.intent.action.VIEW" /> <category android:name="android.intent.category.DEFAULT" /> <category android:name="android.intent.category.BROWSABLE" /> <data android:scheme="http" android:host="*" /> <data android:pathPattern=".*.txt" /> <data android:pathPattern=".*.pdf" /> </intent-filter>
Co oznaczają poszczególne elementy w <data>?
Myślę, że dane atrybuty są jasne, ale dla pewności wyjaśnię:
- mimeType — typ MIME lub Content-Type. Jest to identyfikator formatu pliku. Więcej o tym możesz poczytać tutaj.
- scheme — określa format adresu URL, może przyjąć takie wartości jak http, file, content, ftp, a nawet Twój własny schemat na przykład „myapp”. Aby wywołać Twoją aplikację, adres intenta może wyglądać tak: „myapp://myenv.net/cosTamZrob/”.
- host — określa, który host aplikacja obsługuje. I tak na przykład, możesz mieć kilka aktywności, a każda z nich obsługuje inny host, google.com, myenv.net, facebook.com itd. Uważaj! Jeśli Twój host obsługuje http i https to musisz stworzyć dwa filtry takie same. Jeden z http, a drugi z https.
- pathPattern — ścieżka URL. Głównym problemem głębokich linków w Androidzie są wyrażenia regularne, Są one bowiem bardzo uproszczoną wersją wyrażeń regularnych. Istnieją tylko dwa symbole wieloznaczne. Zobacz dokumentacje. Kolejnym problemem są linki, które zaczynają się od cyfr. Na przykład: myenv.net/page12345, myenv.net/12345. W tym momencie będziesz musiał stworzyć ogromny plik z filtrami i to z każdą podstroną, która posiada cyfry.
<data android:host="www.myenv.net" android:pathPattern="/page1.*/" android:scheme="http" />
Więcej o znacznikach możesz poczytać tutaj.
W jaki sposób pobrać URL?
final Intent intent = getIntent(); final String action = intent.getAction(); if(Intent.ACTION_VIEW.equals(action)){ Uri uri = intent.getData(); String text = "Encoded Path: " + uri.getEncodedPath() + " \n Complete Path: " + uri.toString(); TextView textView = findViewById(R.id.textview); textView.setText(text); }
Podsumowanie
Deep links to koncepcja, która pomaga użytkownikom poruszać się między internetem a aplikacjami lub między samymi aplikacjami. Są to w zasadzie adresy URL, które kierują użytkowników bezpośrednio do określonej zawartości w aplikacji.
Teraz zachęcam Cię do tworzenia własnych filtrów intencji. Niby taka prosta funkcja, a taka skomplikowana. Nie ma prostego sposobu na wyświetlenie aplikacji na liście, jest to uzależnione od obiektu Intent i co w nim się znajduje, jakie atrybuty i wartości przyjmuje. Dlatego często będziesz musiał tworzyć wiele flitów, aby pewna akcja się udała. Gdzie to może się przydać? Oprócz przykładów, które podałem, możesz też tworzyć pliki z własnym rozszerzeniem (na przykład ustawienia aplikacji), a następnie otwierać je w Twojej aplikacji.
Istnieje też prosta biblioteka od Airbnb, która pomaga w tworzeniu deep links. Nadal będziesz musiał dodać wiersze kodu do pliku AndroidManifest. Osobiście nie testowałem tej biblioteki, jeśli miałeś styczność z nią daj znać jak się sprawdza 🙂