Podstawy aplikacji

Aplikacje na Androida można pisać w języku Kotlin – w języku Java oraz w języku C++. Narzędzia pakietu Android SDK kompilowają Twój kod oraz wszelkie pliki danych i zasobów do pliku APK lub pakietu Android App Bundle.

Pakiet na Androida to plik archiwum z sufiksem .apk, który zawiera treść aplikacji na Androida wymaganą w czasie działania. To plik, za pomocą którego urządzenia z Androidem instalują tę aplikację.

Android App Bundle to plik archiwum z sufiksem .aab i zawiera zawartość projektu aplikacji na Androida, w tym dodatkowe metadane, które nie są wymagane w czasie działania. Pakiet aplikacji na Androida jest formatem publikowania i nie można go instalować na urządzeniach z Androidem. Odkłada generowanie i podpisywanie pakietu APK na późniejszy etap.

Jeśli na przykład rozpowszechniasz aplikację w Google Play, serwery Google Play generują zoptymalizowane pliki APK, które zawierają tylko zasoby i kod wymagane przez konkretne urządzenie, na którym chcesz ją zainstalować.

Każda aplikacja na Androida działa we własnej bezpiecznej piaskownicy, chronionej przez te funkcje zabezpieczeń:

  • Android to wieloosobowy system Linux, w którym każda aplikacja jest innym użytkownikiem.
  • Domyślnie system przypisuje każdej aplikacji unikalny identyfikator użytkownika na urządzeniach z systemem Linux, który jest używany tylko przez system i nie jest aplikacji. System ustawia uprawnienia do wszystkich plików w aplikacji, tak aby dostęp do wszystkich plików miał tylko identyfikator użytkownika przypisany do tej aplikacji.
  • Każdy proces ma własną maszynę wirtualną, więc kod aplikacji działa niezależnie od innych aplikacji.
  • Domyślnie każda aplikacja działa w obrębie własnego procesu Linuxa. System Android rozpoczyna ten proces, gdy musi wykonać dowolny z komponentów aplikacji, a następnie wyłącza go, gdy nie jest już potrzebny lub gdy system musi odzyskać pamięć na potrzeby innych aplikacji.

System Android stosuje zasadę jak najmniejszych uprawnień. Oznacza to, że domyślnie każda aplikacja ma dostęp tylko do tych komponentów, które są jej niezbędne do działania, a nie więcej. W ten sposób powstaje bardzo bezpieczne środowisko, w którym aplikacja nie ma dostępu do części systemu, do których nie ma uprawnień.

Istnieją jednak sposoby udostępniania danych innym aplikacjom, a aplikacji dostępu do usług systemowych:

  • 2 aplikacje mogą mieć ten sam identyfikator użytkownika systemu Linux. W takim przypadku obie aplikacje mają dostęp do swoich plików. Aby oszczędzać zasoby systemowe, aplikacje z tym samym identyfikatorem użytkownika mogą działać w ramach tego samego procesu Linuksa i współdzielić tę samą maszynę wirtualną. Aplikacje muszą być też podpisane tym samym certyfikatem.
  • Aplikacja może poprosić o dostęp do danych urządzenia, takich jak jego lokalizacja, aparat i połączenie Bluetooth. Użytkownik musi jawnie przyznać te uprawnienia. Więcej informacji o uprawnieniach znajdziesz w artykule Uprawnienia na Androidzie.

W pozostałej części tego dokumentu omawiamy następujące zagadnienia:

  • Podstawowe komponenty platformy, które definiują Twoją aplikację.
  • Plik manifestu, w którym deklarujesz komponenty i wymagane funkcje urządzenia dla aplikacji.
  • Zasoby, które są niezależne od kodu aplikacji i pozwalają aplikacji płynnie optymalizować działanie pod kątem różnych konfiguracji urządzeń.

Komponenty aplikacji

Komponenty aplikacji to podstawowe elementy aplikacji na Androida. Każdy komponent to punkt wejścia, przez które system lub użytkownik może wejść do aplikacji. Niektóre komponenty zależą od innych.

Są 4 typy komponentów aplikacji:

  • Ćwiczenia
  • Usługi
  • Odbiorniki transmisji
  • Dostawcy treści

Każdy typ służy do innego celu i ma własny cykl życia, który określa sposób tworzenia i niszczenia komponentu. W sekcjach poniżej opisujemy 4 typy komponentów aplikacji.

Aktywności
Aktywność to punkt wejścia w interakcję z użytkownikiem. Reprezentuje jeden ekran z interfejsem użytkownika. Na przykład aplikacja do obsługi poczty e-mail może mieć jedną aktywność – listę nowych e-maili, kolejną aktywność związaną z tworzeniem e-maila i drugą – odczytywanie e-maili. Chociaż działania te wspólnie tworzą spójne wrażenia użytkownika w aplikacji do poczty e-mail, każda z nich jest niezależna od pozostałych.

Inna aplikacja może uruchomić dowolną z tych aktywności, jeśli zezwala na to aplikacja do poczty e-mail. Na przykład aplikacja aparatu może uruchomić w aplikacji do poczty e-mail działanie polegające na napisaniu nowego e-maila, aby umożliwić użytkownikowi udostępnienie zdjęcia.

Aktywność umożliwia wykonywanie tych kluczowych interakcji między systemem a aplikacją:

  • śledzenie tego, na czym aktualnie zależy użytkownikowi (co jest widoczne na ekranie), aby system nadal działał w procesie hostowania aktywności.
  • Wiedza na temat wcześniej używanych procesów zawiera zatrzymane działania, do których użytkownik może wrócić, i nadanie im większego priorytetu, aby były dostępne.
  • Pomaganie aplikacji w zatrzymaniu procesu, aby użytkownik mógł wrócić do działań w poprzednim stanie.
  • Umożliwienie aplikacjom implementowania przepływów użytkowników między sobą, a systemom – koordynowania tych przepływów. Głównym przykładem jest udostępnianie.

Wdrażasz aktywność jako podklasę klasy Activity. Więcej informacji o klasie Activity znajdziesz w artykule Wprowadzenie do działań.

Usługi
Usługa to ogólny punkt wejścia, za pomocą którego aplikacja może działać w tle z różnych powodów. Jest to komponent, który działa w tle, aby wykonywać długotrwałe operacje lub wykonywać zadania zdalne. usługa nie ma interfejsu użytkownika,

Na przykład usługa może odtwarzać muzykę w tle, gdy użytkownik korzysta z innej aplikacji, lub pobierać dane przez sieć bez blokowania aktywności użytkownika. Inny komponent, np. aktywność, może uruchomić usługę i umożliwić jej uruchomienie lub powiązanie z nią, aby nawiązać z nią interakcję.

Istnieją 2 typy usług, które informują system, jak zarządzać aplikacją: uruchomione usługi i powiązane usługi.

Uruchomione usługi informują system, że ma działać do momentu zakończenia pracy. Może to być synchronizacja niektórych danych w tle lub odtwarzanie muzyki nawet po zamknięciu aplikacji przez użytkownika. Synchronizowanie danych w tle czy odtwarzanie muzyki to różne typy uruchomionych usług, które system obsługuje w różny sposób:

  • Użytkownik jest bezpośrednio świadomy odtwarzania muzyki. Aplikacja przekazuje to do systemu, wskazując, że urządzenie ma być na pierwszym planie, i powiadamiać użytkownika o tym, że urządzenie jest uruchomione. W takim przypadku system traktuje priorytetowo działanie procesu tej usługi, ponieważ wyłączenie tej usługi może być nieprzydatne dla użytkownika.
  • Zwykłe usługi działające w tle nie są bezpośrednio znane użytkownikowi, więc system ma większą swobodę w zarządzaniu swoimi procesami. Może umożliwić jej zamknięcie i ponowne uruchomienie usługi później, jeśli będzie potrzebować pamięci RAM do obsługi rzeczy, które bardziej interesują użytkownika.

Usługi graniczne działają, ponieważ inna aplikacja (lub system) zgłosiła chęć korzystania z tej usługi. Usługa powiązana zapewnia interfejs API dla innego procesu, a system wie, że istnieje zależność między tymi procesami. Jeśli więc proces A jest powiązany z usługą w procesie B, system wie, że musi utrzymywać proces B i jego usługę dla A. Co więcej, jeśli proces A jest dla użytkownika ważny, oznacza to, że należy go traktować jako coś, na czym on także zależy.

Dzięki swojej elastyczności usługi są przydatnymi elementami składowymi wszelkich ogólnikowych koncepcji systemowych. Animowane tapety, urządzenia do odsłuchiwania powiadomień, wygaszacze ekranu, metody wprowadzania tekstu, usługi ułatwień dostępu i wiele innych podstawowych funkcji systemu składają się z usług zaimplementowanych w aplikacjach i związanych z nim przez system podczas działania.

Usługa jest zaimplementowana jako podklasa klasy Service. Więcej informacji o klasie Service znajdziesz w opisie usług.

Uwaga: jeśli Twoja aplikacja jest kierowana na Androida 5.0 (poziom interfejsu API 21) lub nowszego, do planowania działań użyj klasy JobScheduler. JobScheduler korzysta z oszczędzania baterii, ponieważ optymalnie ustala harmonogram zadań w celu zmniejszenia zużycia energii oraz korzysta z interfejsu API Doze. Więcej informacji o korzystaniu z tej klasy znajdziesz w dokumentacji referencyjnej JobScheduler.

Odbiorniki
Odbiornik transmisji to komponent, który umożliwia systemowi dostarczanie zdarzeń do aplikacji poza zwykłym procesem użytkownika, dzięki czemu aplikacja może reagować na komunikaty systemowe. Odbiorniki to kolejne dobrze zdefiniowane wejście do aplikacji, więc system może dostarczać komunikaty nawet do aplikacji, które nie są obecnie uruchomione.

Na przykład aplikacja może zaplanować alarm, aby opublikować powiadomienie o zbliżającym się wydarzeniu. Ponieważ alarm jest dostarczany na urządzenie BroadcastReceiver w aplikacji, nie musi pozostawać uruchomiona, dopóki alarm się nie włączy.

Wiele z nich jest pochodzących z systemu, np. informujący o wyłączeniu ekranu, słabej baterii lub tym, że zostało zrobione zdjęcie. Aplikacje mogą też inicjować komunikaty, np. powiadamiać inne aplikacje, że na urządzenie są pobierane niektóre dane i są dostępne.

Mimo że odbiorniki nie wyświetlają interfejsu użytkownika, mogą utworzyć powiadomienie na pasku stanu, aby ostrzec użytkownika przed rozpoczęciem transmisji. Częściej jednak odbiornik jest po prostu bramą do innych komponentów i służy do wykonywania bardzo minimalnej pracy.

Na przykład odbiornik może zaplanować wykonanie działania JobService na podstawie zdarzenia za pomocą metody JobScheduler. Odbiorniki transmisji często zawierają interakcje w aplikacjach, dlatego warto wziąć pod uwagę wpływ ich konfiguracji na bezpieczeństwo.

Odbiornik jest zaimplementowany jako podklasa klasy BroadcastReceiver, a każda transmisja jest dostarczana jako obiekt Intent. Więcej informacji znajdziesz w klasie BroadcastReceiver.

Dostawcy treści
Dostawca treści zarządza wspólnym zbiorem danych aplikacji, które możesz przechowywać w systemie plików, bazie danych SQLite, w internecie lub w dowolnym innym miejscu w pamięci trwałej, do którego aplikacja ma dostęp. Za pośrednictwem dostawcy treści inne aplikacje mogą wysyłać zapytania lub modyfikować dane, jeśli dostawca treści na to zezwala.

Na przykład system Android zapewnia dostawcę treści, który zarządza informacjami kontaktowymi użytkownika. Każda aplikacja z odpowiednimi uprawnieniami może wysyłać zapytania do dostawcy treści, np. używać ContactsContract.Data, aby odczytywać i zapisywać informacje o konkretnej osobie.

To dość kuszące, aby traktować dostawcę treści jak abstrakcyjny element bazy danych, ponieważ oferuje on wbudowane interfejsy API i obsługę dla tego typowego przypadku. Mają one jednak inny podstawowy cel z punktu widzenia projektowania systemu.

Dostawca treści to dla systemu punkt wejścia do aplikacji służący do publikowania nazwanych elementów danych identyfikowanych za pomocą schematu URI. Aplikacja może więc określić sposób mapowania zawartych w niej danych na przestrzeń nazw URI, przekazując te identyfikatory innym podmiotom, które z kolei mogą z nich korzystać do uzyskiwania dostępu do danych. Dzięki temu system może zarządzać aplikacją na kilka konkretnych sposobów:

  • Przypisanie identyfikatora URI nie wymaga, aby aplikacja pozostała uruchomiona, więc identyfikatory URI mogą być zachowywane po zamknięciu aplikacji będącej ich właścicielem. System musi się tylko upewnić, że aplikacja będąca właścicielem wciąż działa, gdy pobiera dane aplikacji z odpowiedniego identyfikatora URI.
  • Te identyfikatory URI stanowią też ważny szczegółowy model zabezpieczeń. Aplikacja może na przykład umieścić identyfikator URI obrazu znajdującego się w schowku, ale pozostawić dostawcę treści zablokowany, aby inne aplikacje nie miały do niego swobodnego dostępu. Gdy druga aplikacja spróbuje uzyskać dostęp do tego identyfikatora URI w schowku, system może zezwolić tej aplikacji na dostęp do danych za pomocą tymczasowego przyznania uprawnień URI. Dzięki temu będzie mieć dostęp tylko do danych powiązanych z tym identyfikatorem URI, a nie do żadnych innych danych w drugiej aplikacji.

Dostawcy treści przydają się też do odczytywania i zapisywania danych, które są prywatne i nie są udostępniane w aplikacji.

Dostawca treści jest implementowany jako podklasa klasy ContentProvider i musi wdrożyć standardowy zestaw interfejsów API, które umożliwiają innym aplikacjom wykonywanie transakcji. Więcej informacji znajdziesz w przewodniku dla programistów dotyczącym dostawców treści.

Każda aplikacja może uruchamiać komponent innej aplikacji. Jeśli na przykład chcesz, aby użytkownik zrobił zdjęcie aparatem urządzenia, istnieje inna aplikacja, która to umożliwia. Aplikacja może używać jej zamiast samodzielnie tworzyć aktywność do zrobienia zdjęcia. Nie musisz dodawać kodu z aplikacji Aparat ani podawać do niego linku. Zamiast tego możesz uruchomić w niej czynność, która powoduje zrobienie zdjęcia. Gotowe zdjęcie jest nawet zwracane do aplikacji, więc możesz go użyć. Użytkownikowi wydaje się, że aparat jest częścią aplikacji.

Gdy system uruchamia komponent, uruchamia proces dla tej aplikacji, jeśli nie jest on jeszcze uruchomiony, i tworzy wystąpienia klas niezbędnych dla komponentu. Jeśli na przykład aplikacja rozpoczyna działanie w aplikacji aparatu, która robi zdjęcie, to działanie to jest wykonywane w ramach procesu należącego do aplikacji aparatu, a nie do procesu aplikacji. Dlatego w przeciwieństwie do aplikacji w większości innych systemów aplikacje na Androida nie mają jednego punktu wejścia: nie mają funkcji main().

System uruchamia każdą aplikację w osobnym procesie z uprawnieniami do plików, które ograniczają dostęp do innych aplikacji. Dlatego aplikacja nie może bezpośrednio aktywować komponentu z innej aplikacji. System jednak może to zrobić. Aby aktywować komponent w innej aplikacji, należy dostarczyć do systemu komunikat, który określa Twój inten, aby uruchomić dany komponent. System aktywuje komponent za Ciebie.

Aktywuj komponenty

Wiadomość asynchroniczna o nazwie intent aktywuje 3 z 4 typów komponentów: działania, usługi i odbiorniki. Intencje łączą ze sobą poszczególne komponenty w czasie działania. Można ich wyobrazić sobie jako komunikatorów, który proszą o działanie z innych komponentów, niezależnie od tego, czy komponent należy do aplikacji, czy do innego.

Intencja jest tworzona za pomocą obiektu Intent, który definiuje wiadomość do aktywacji określonego komponentu (intencja jawna) lub konkretnego typu komponentu (intencja ukryta).

W przypadku działań i usług intencja definiuje działanie do wykonania, np. wyświetlenie lub wysłanie, i może określać identyfikator URI danych, na których ma on działać, oraz informacje, które może znać uruchamiany komponent.

Intencja może np. przekazywać żądanie, aby pokazało się obraz lub otworzyło stronę internetową. W niektórych przypadkach, aby otrzymać wynik, możesz rozpocząć działanie. W takim przypadku działanie to również zwróci wynik w funkcji Intent. Możesz też zezwolić użytkownikowi na wybranie osobistego kontaktu, a następnie prośba o jego zwrot. Intencja zwracana zawiera identyfikator URI wskazujący na wybrany kontakt.

W przypadku odbiorców transmisji intencja określa ogłoszenie transmisji. Przykładowo komunikat o słabej baterii będzie zawierać tylko znany ciąg znaków, który wskazuje, że poziom naładowania baterii jest niski.

W przeciwieństwie do czynności, usług i odbiorników dostawca treści jest aktywowany po otrzymaniu żądania z ContentResolver. Moduł do rozpoznawania treści obsługuje wszystkie transakcje bezpośrednie z dostawcą treści, a komponent przeprowadza transakcje z metodami dostawcy w obiekcie ContentResolver. Zapewnia to wysoki poziom abstrakcji między dostawcą treści a komponentem żądającym informacji.

Każdy typ komponentu można aktywować w inny sposób:

  • Możesz rozpocząć działanie lub dać mu coś nowego, przekazując Intent do startActivity() lub, jeśli aktywność ma zwracać wynik, startActivityForResult().
  • W Androidzie 5.0 (poziom interfejsu API 21) i nowszych możesz planować działania za pomocą klasy JobScheduler. W przypadku wcześniejszych wersji Androida możesz uruchomić usługę lub przekazać nowe instrukcje trwającej usłudze, przekazując żądanie Intent do startService(). Możesz powiązać ją z usługą, przekazując Intent do bindService().
  • Możesz zainicjować transmisję, przekazując Intent do metod takich jak sendBroadcast() lub sendOrderedBroadcast().
  • Zapytanie do dostawcy treści możesz wysłać za pomocą wywołania query() na ContentResolver.

Więcej informacji o korzystaniu z intencji znajdziesz w dokumentacji intencji i filtrów intencji. Więcej informacji o aktywowaniu określonych komponentów znajdziesz w tych dokumentach: Wprowadzenie do aktywności, Omówienie usług, BroadcastReceiver i Dostawcy treści.

Plik manifestu

Zanim system Android będzie mógł uruchomić komponent aplikacji, system musi wiedzieć, że komponent istnieje. W tym celu musi odczytać plik manifestu aplikacji (AndroidManifest.xml). Wszystkie swoje komponenty aplikacji deklarują w tym pliku, który znajduje się w katalogu głównym katalogu projektu aplikacji.

Oprócz deklarowania komponentów plik manifestu wykonuje też wiele innych działań, na przykład:

  • Określa wszystkie uprawnienia użytkownika wymagane przez aplikację, takie jak dostęp do internetu czy dostęp do odczytu kontaktów użytkownika.
  • Deklaruje minimalny poziom interfejsu API wymagany przez aplikację w zależności od interfejsów API używanych przez aplikację.
  • Deklaruje sprzęt i funkcje oprogramowania używane lub wymagane przez aplikację, np. aparat, usługi Bluetooth czy ekran wielodotykowy.
  • Deklaruje biblioteki interfejsów API, z którymi aplikacja musi być połączona (inne niż interfejsy API platformy Android), np. biblioteka Map Google.

Deklarowanie komponentów

Głównym zadaniem pliku manifestu jest informowanie systemu o komponentach aplikacji. Na przykład plik manifestu może zadeklarować działanie w ten sposób:

<?xml version="1.0" encoding="utf-8"?>
<manifest ... >
    <application android:icon="@drawable/app_icon.png" ... >
        <activity android:name="com.example.project.ExampleActivity"
                  android:label="@string/example_label" ... >
        </activity>
        ...
    </application>
</manifest>

W elemencie <application> atrybut android:icon wskazuje zasoby ikony identyfikującej aplikację.

W elemencie <activity> atrybut android:name określa pełną i jednoznaczną nazwę klasy podklasy Activity, a atrybut android:label – ciąg znaków, który ma być etykietą widoczną dla użytkownika dla aktywności.

Wszystkie komponenty aplikacji musisz zadeklarować, używając tych elementów:

Aktywności, usługi i dostawcy treści, których wskazano w źródle, ale nie deklarujesz w pliku manifestu, nie są widoczne dla systemu i w konsekwencji nie mogą być uruchamiane. Można jednak je zadeklarować w pliku manifestu lub utworzyć dynamicznie w kodzie BroadcastReceiver jako obiekty i zarejestrować w systemie, wywołując metodę registerReceiver().

Więcej informacji o tym, jak uporządkować plik manifestu aplikacji, znajdziesz w artykule Omówienie pliku manifestu aplikacji.

Deklarowanie możliwości komponentu

Jak wspomnieliśmy w sekcji Aktywuj komponenty, za pomocą Intent możesz uruchamiać działania, usługi i odbiorniki. Możesz to zrobić, bezpośrednio nadając nazwę komponentowi docelowemu, używając w intencji nazwy klasy komponentu. Możesz też użyć intencji niejawnej, która opisuje typ działania do wykonania oraz (opcjonalnie) dane, na których chcesz je wykonać. Intencja niejawna umożliwia systemowi znalezienie na urządzeniu komponentu, który może wykonać działanie i je uruchomić. Jeśli wiele komponentów może wykonać działanie opisane w zamiarze, użytkownik wybiera, którego z nich użyje.

Uwaga: jeśli chcesz uruchomić Service, upewnij się, że aplikacja jest bezpieczna, używając intencji wyraźnej. Korzystanie z niejawnej intencji uruchomienia usługi stanowi zagrożenie dla bezpieczeństwa, ponieważ nie można mieć pewności, która usługa odpowiada na intencję, a użytkownik nie będzie w stanie zobaczyć, która usługa się uruchamia. Począwszy od Androida 5.0 (poziom interfejsu API 21) system zgłasza wyjątek, jeśli wywołujesz bindService() z intencją niejawną. Nie deklaruj filtrów intencji dla swoich usług.

System identyfikuje komponenty, które mogą odpowiadać na intencję, porównując otrzymaną intencję z filtrami intencji podanymi w pliku manifestu innych aplikacji na urządzeniu.

Gdy zadeklarujesz aktywność w pliku manifestu aplikacji, możesz opcjonalnie dodać filtry intencji, które deklarują możliwości tego działania, co umożliwi odpowiadanie na intencje z innych aplikacji. Aby to zrobić, dodaj element <intent-filter> jako element podrzędny elementu deklaracji komponentu.

Jeśli na przykład tworzysz aplikację do poczty e-mail z aktywnością związaną z tworzeniem nowego e-maila, możesz zadeklarować filtr intencji, który odpowiada na intencje „wyślij” w celu wysłania nowego e-maila, jak w tym przykładzie:

<manifest ... >
    ...
    <application ... >
        <activity android:name="com.example.project.ComposeEmailActivity">
            <intent-filter>
                <action android:name="android.intent.action.SEND" />
                <data android:type="*/*" />
                <category android:name="android.intent.category.DEFAULT" />
            </intent-filter>
        </activity>
    </application>
</manifest>

Jeśli inna aplikacja utworzy intencję z działaniem ACTION_SEND i przekaże ją do startActivity(), system może rozpocząć Twoją aktywność, aby użytkownik mógł utworzyć wersję roboczą i wysłać e-maila.

Więcej informacji o tworzeniu filtrów intencji znajdziesz w artykule Intencje i filtry intencji.

Deklarowanie wymagań aplikacji

Istnieje wiele urządzeń z Androidem i nie wszystkie mają takie same funkcje. Aby uniemożliwić instalowanie aplikacji na urządzeniach, na których nie ma funkcji potrzebnych do działania, musisz wyraźnie określić profil dla typów urządzeń obsługiwanych przez aplikację, zadeklarując w pliku manifestu wymagania dotyczące urządzenia i oprogramowania.

Większość z tych deklaracji ma wyłącznie charakter informacyjny. System ich nie odczytuje, ale usługi zewnętrzne, np. Google Play, odczytują je, aby umożliwić użytkownikom filtrowanie aplikacji, gdy szukają aplikacji na urządzeniu.

Załóżmy np., że Twoja aplikacja wymaga aparatu i korzysta z interfejsów API wprowadzonych w Androidzie 8.0 (poziom API 26). Musisz zadeklarować te wymagania. Wartości minSdkVersion i targetSdkVersion są ustawione w pliku build.gradle modułu aplikacji:

android {
  ...
  defaultConfig {
    ...
    minSdkVersion 26
    targetSdkVersion 29
  }
}

Uwaga: nie ustawiaj minSdkVersion i targetSdkVersion bezpośrednio w pliku manifestu, ponieważ podczas procesu kompilacji są one zastępowane przez Gradle. Więcej informacji znajdziesz w artykule Określanie wymagań dotyczących poziomu interfejsu API.

Funkcję aparatu zadeklarujesz w pliku manifestu aplikacji:

<manifest ... >
    <uses-feature android:name="android.hardware.camera.any"
                  android:required="true" />
    ...
</manifest>

Zgodnie z deklaracjami przedstawionymi w tych przykładach urządzenia, które nie mają aparatu lub mają Androida w wersji niższej niż 8.0, nie mogą instalować aplikacji z Google Play. Możesz też zadeklarować, że aplikacja korzysta z aparatu, ale go nie wymaga. Aby to zrobić, ustaw atrybut required na false, sprawdź w czasie działania, czy urządzenie ma kamerę, i w razie potrzeby wyłącz wszystkie funkcje kamery.

Więcej informacji o zarządzaniu zgodnością aplikacji z różnymi urządzeniami znajdziesz w artykule Omówienie zgodności urządzeń.

Zasoby aplikacji

Aplikacja na Androida składa się nie tylko z kodu. Wymaga zasobów, które są niezależne od kodu źródłowego, np. obrazów, plików audio czy innych elementów związanych z wizualną prezentacją aplikacji. Za pomocą plików XML możesz np. zdefiniować animacje, menu, style, kolory i układ interfejsów aktywności.

Korzystanie z zasobów aplikacji ułatwia aktualizowanie różnych cech aplikacji bez modyfikowania kodu. Udostępnienie zestawów alternatywnych zasobów pozwala zoptymalizować aplikację pod kątem różnych konfiguracji urządzeń, takich jak różne języki i rozmiary ekranu.

Dla każdego zasobu uwzględnionego w projekcie Androida narzędzia do kompilacji SDK definiują unikalny identyfikator całkowitą, za pomocą którego możesz się odwoływać do zasobu z kodu aplikacji lub z innych zasobów zdefiniowanych w formacie XML. Jeśli na przykład aplikacja zawiera plik graficzny o nazwie logo.png (zapisany w katalogu res/drawable/), narzędzia pakietu SDK wygenerują identyfikator zasobu o nazwie R.drawable.logo. Ten identyfikator jest mapowany na liczbę całkowitą w konkretnej aplikacji, której możesz użyć, by odwołać się do obrazu i wstawić go w interfejsie.

Jednym z najważniejszych aspektów udostępniania zasobów niezależnie od kodu źródłowego jest możliwość zapewnienia alternatywnych zasobów do różnych konfiguracji urządzeń.

Na przykład definiując ciągi znaków interfejsu w pliku XML, możesz przetłumaczyć je na inne języki i zapisać w oddzielnych plikach. Następnie Android zastosuje odpowiednie ciągi znaków do Twojego interfejsu na podstawie kwalifikatora języka, który dodajesz do nazwy katalogu zasobów, np. res/values-fr/ w przypadku francuskich wartości ciągu znaków i ustawień języka użytkownika.

Android obsługuje wiele kwalifikatorów dla alternatywnych zasobów. Kwalifikator to krótki ciąg znaków umieszczany w nazwie katalogów zasobów, aby określić konfigurację urządzeń, do której będą używane te zasoby.

Możesz na przykład tworzyć różne układy aktywności w zależności od orientacji i rozmiaru ekranu urządzenia. Jeśli ekran urządzenia jest pionowo (wysoki), warto mieć układ z przyciskami ustawionymi pionowo. Jeśli natomiast ekran ma orientację poziomą, przyciski warto wyrównać poziomo. Aby zmienić układ w zależności od orientacji, możesz zdefiniować dwa układy i zastosować odpowiedni kwalifikator do nazw katalogów w każdym układzie. Następnie system automatycznie zastosuje odpowiedni układ w zależności od bieżącej orientacji urządzenia.

Więcej informacji o różnych rodzajach zasobów, które można uwzględnić w aplikacji, oraz o tym, jak tworzyć zasoby alternatywne dla różnych konfiguracji urządzeń, znajdziesz w omówieniu zasobów aplikacji. Więcej informacji o sprawdzonych metodach i projektowaniu solidnych aplikacji o jakości produkcyjnej znajdziesz w Przewodniku po architekturze aplikacji.

Dodatkowe materiały

Jeśli chcesz nauczyć się programować na Androida przy użyciu filmów i samouczków dotyczących kodu, zapoznaj się z kursem Udacity Developing Android Apps with Kotlin (Tworzenie aplikacji na Androida przy użyciu Kotlin).

Przeczytaj więcej na te tematy:

Intencje i filtry intencji
Dowiedz się, jak używać interfejsów API Intent do aktywowania komponentów aplikacji, takich jak działania i usługi, oraz jak udostępniać komponenty aplikacji innym aplikacjom.
Wprowadzenie do zadań
Dowiedz się, jak utworzyć instancję klasy Activity, która udostępnia w aplikacji osobny ekran z interfejsem użytkownika.
Omówienie zasobów aplikacji
Dowiedz się, jak struktura aplikacji na Androida pozwala oddzielić zasoby aplikacji od jej kodu oraz jak udostępnić alternatywne zasoby na potrzeby konkretnych konfiguracji urządzeń.

Inne ważne informacje:

Omówienie zgodności urządzeń
Dowiedz się, jak Android działa na różnych typach urządzeń i jak możesz zoptymalizować aplikację pod kątem każdego urządzenia lub ograniczyć dostępność aplikacji na różnych urządzeniach.
Uprawnienia na Androidzie
Dowiedz się, jak Android ogranicza dostęp aplikacji do określonych interfejsów API za pomocą systemu uprawnień, który wymaga zgody użytkownika na korzystanie przez Twoją aplikację z tych interfejsów.