Deep Links czyli 'Odtwórz za pomocą”

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 🙂

Co dalej?

  • Polub stronę MYENV na Facebooku oraz śledź mnie na Twitterze
  • Zachęcam do komentowania i pisania propozycji tematów, o których chcesz przeczytać
  • Poleć ten wpis za pomocą poniższych przycisków. Będę Ci za to bardzo wdzięczny 🙂
  • Życzę Ci miłego dnia i miłego kodowania 🙂