🔏
AppSec & Pentest
Mobile
Mobile
  • Mobile
  • Pentesting Methodology
  • Programming
    • Аналитика
      • Some Papers
      • Примеры токенов/ключей и тп
      • Twitter ads
      • Branch.IO
      • Adjust
      • Amplitude Analytics
      • Paypal for Business
      • Emarsys
      • MobileAppTracker
      • AppsFlyer
        • About
        • Настройка аккаунта
        • Исследование кода
        • Examples
      • Fabric
      • Mixpanel Analytics
      • Facebook ads
      • Yandex
      • Firebase SDK
        • Intro
        • Примеры
        • Firebase Cloud Messaging
        • Компоненты
          • Firebase
          • FirebaseABTesting
          • FirebaseAnalytics[Interop]
          • FirebaseAppDistribution
          • FirebaseAuth[Interop]
          • FirebaseCore
          • FirebaseCoreDiagnostics[Interop]
          • FirebaseCrashlytics
          • FirebaseDatabase
          • FirebaseDynamicLinks
          • FirebaseFirestore[Swift]
          • FirebaseFunctions
          • FirebaseInAppMessaging
          • FirebaseInstallations
          • FirebaseInstanceID
          • FirebaseMessaging
          • FirebaseRemoteConfig
          • FirebaseStorage[Swift]
          • GoogleDataTransport
          • GoogleDataTransportCCTSupport
          • GoogleUtilities
          • GoogleUtilitiesComponents
      • Crashlytics
      • GTM: Google Tag Manager
      • Google Maps
      • Google Analytics
      • Flurry
      • HockeyApp
    • iOS
      • Материалы
      • iOS: SSL Pinning
      • ЯП
        • Swift
          • VIPER (Architecture)
          • Общее
          • UI
          • Производительность
          • Swift Style Guide
        • Swift Security
          • Примеры уязвимостей
      • Frameworks and Libraries
        • [Pentest] App extensions
          • About
          • Extension types
          • Static Analys
          • Dynamic Analys
        • [Pentest] App Notifications
        • Async
        • СDP
        • Core
        • Cryptography
        • Jailbreak Detection
        • Network
          • AFNetworking
          • Alamofire
          • HTTP Requests
        • Other
        • Push
        • RxSwift
        • Store Data
        • UI
          • SwiftUI
          • WebView in iOS App
          • UI
        • VPN Detection
      • XCode
        • Build Project
        • Build Project via Command Line
        • Install IPA
        • Templates
      • Другие инструменты
        • mint
      • Системы зависимостей пакетов
        • Carthage
        • CocoaPods
      • Troubleshooting
    • Android
      • Архитектура Android приложения
        • Архитектура Kotlin-приложения
        • Разница между Android Library, Android APP и Java Library
        • Basic
          • Activities
          • Broadcast Receivers
          • Content Providers
          • Custom URL Schemes
          • Intents
          • Notifications
          • PendingIntents
          • Permissions
          • Services
          • Android WebView
      • ЯП
        • Java
          • Bundle
        • Kotlin
          • Возвращение объектов в Intent
          • Call Native Functions
      • Frameworks
        • AndroidX
        • LiveData
        • Lifecycle
        • Background Tasks
          • DownloadManager
          • AlarmManager
          • Foreground Services (или просто Services)
          • WorkManager
        • Room
        • Data binding
          • Basic
        • NDK
          • Install and Build
          • OpenSSL
          • libgit2 build
        • Navigation
        • Работа с изображениями
          • Glide
        • Video/Audio
          • Communications
            • Jitsi
        • JS Engines
          • FB: Hermes
          • Duktape
        • DI: Dependency Injection
          • Зачем?
          • koin
          • kodein
          • dagger2
        • Retrofit / OkHTTP
          • Intro
          • Example Usage
            • Parse error body
            • Примеры обработчиков запросов
            • Структура модуля
            • HttpApi
            • ControllerApi
          • SSLPinning
        • Google Play Authorization
      • Automating build (android in docker)
      • Android Studio
        • Build Project
        • Составные части проекта
      • Технологии
        • LeakCanary
        • Mocking
        • Настройка резервного копирования
        • Remote Method Invocation
        • bundletool (aab -> apk)
      • Примеры приложений
        • Kotlin
      • API levels & NDK Version
    • PWA
    • Hybrid App
      • Frameworks
        • Frameworks List
        • Electron
        • React Native
      • Google Web Toolkit
      • Dart/Flutter
      • Kotlin
      • Game Develope
    • Рекомендации
      • Хранение PIN-кода и шифрование информации
      • Разработка приложения для людей с ограниченными возможностями
      • Secure Networking on iOS
    • AirWatch MDM
    • Дистрибьюция
      • AppCenter
      • App Store
      • App Store Connect
      • AppTester
      • Crashlytics
      • Cydia
      • Diawi
      • Google Play
      • Hockey App
      • TestFairy
      • TestFlight
      • Transporter.app
      • Firebase AppDistribution
  • Forensic
    • Bluetooth
    • NFC
    • GSM
    • SIM-cards
    • iOS
      • Инструменты и скрипты
        • Забор скриншотов с телефона
        • otool
        • lipo
        • plist reader
        • backup reader
        • libimobiledevice
        • Cydia Impactor
        • App Signature
      • Архитектура ОС
        • Шифрование приложений
        • Архитектура iOS приложения
        • iBoot
        • Secure Enclave (SEP)
        • Браузеры
      • Файловая система
        • Где что хранится
        • Мониторинг файловой системы
      • Create/Decrypt Backup
      • IPA dump
        • Frida IPA dump
        • iOS 11 и выше
        • Младше iOS 10
      • Jailbreak
      • DFU режим (режим восстановления и обновления)
    • Android
      • Файловая система
        • Android KeyStore
      • Общая информация о системе: Полезные тулзы и команды
      • Проверить подписи apk
      • Создание и восстановление резервной копии
      • Память процессов
      • Root
        • Common
        • A/B-разделы
        • Su
        • TWRP
  • Pentest
    • Уязвимости и Атаки
      • Изи баги
      • Common
      • iOS
      • Android
      • AppLinks
      • Auth
        • Biometrics bypass
        • PIN Bruteforce
        • Типичные ошибки реализации SMS-аутентификации
      • USSD Attack
      • Java Object Deserialization
      • Lack of binary protection (anti-debugging) controls
      • Disabled security features in binary libraries
      • Lack of exploit mitigations (e.g. PIE, ARC, or stack canaries)
      • Path disclosure in the binary
      • Runtime hacking exploits (e.g. exploits that are only possible in a jailbroken environment)
      • Snapshot/pasteboard leakage
      • User data stored unencrypted in the file system and/or external storage
      • Android Task Hijacking
      • WebView
        • Check list
        • Example Web View XSS in iOS app
        • CVE-2020-6506: uXSS in Android WebView
    • Кейсы
      • Общие
        • Firebase
        • Про сниффинг трафика HTTP2/gRPC
        • Dump memory
      • Android
        • Simple Library RCE for Android
        • Закинуть GApps на эмулятор
        • Android Dependency Check
        • Запрет скриншота и детект оверлея
        • Disable/Delete any app w/o root
      • iOS
        • App Transport Security
        • Info.plist
        • Смотреть логи
        • Установка IPA-образа на iOS без XCode, Cydia Impactor
        • Борьба со скриншотами
        • Блюринг изображений в менеджере окон
        • Установка неподписанных IPA
      • Hybrid Apps
        • Flutter SDK: RE/Capture Traffic
    • Bug Bounty
    • Настройка окружения
      • SASTs
      • Frida & Objection
      • Pentest WebView
      • iOS
        • Platform
        • Network
          • Запись траффика iOS
          • iOS SSL Unpinning
      • Android
        • Reverse Engineering
        • Platform
        • Network
          • Запись трафика Android
          • Android: SSL Unpinning
    • Mitigations
    • Books & Papers
    • Companies & People & Blogs
    • Инструменты и скрипты
      • Комбайны
      • Android
        • grep: Извлечение информации из APK
        • Более менее
        • Старая херня
          • Drozer
          • Разное
      • iOS
        • SAST
          • ipanema
          • iblessing
        • meetle
        • Static Analys with Frida
        • iFunBox
        • iOS Binary Analysis
        • needle
        • idb
        • ios emulator
        • passionfruit
        • Grapefruit ("NG passionfruit")
        • XPC Sniffing
        • SAST in MobSF
        • Поиск по файлам
      • hybrid app
        • Cordova
        • Xamarin
        • Electron
      • FBFlipper
      • truegaze
  • Reverse Engineering
    • Android
      • Tools
        • Decompilers
        • TODO: Androguard
        • TODO: AndroPyTool
        • TODO: LIEF-project
        • TODO: MobSF
        • JADX
        • dex2jar
        • Diff APKs, JARs,..
        • APKiD
        • enjarify
        • adb/fastboot
          • Install
          • Usage
          • Troubleshooting
          • На что можем влиять через adb (в поисках сервисов)
        • DexCalibur
      • Объединить несколько JAR
      • Build AOSP in Docker
      • Патчинг
      • Поиск уникальных строк в Smali
      • Защита от frida
    • iOS
      • CVEs
      • Tools
        • iRET
        • xcrun
        • otool: check binary encryption
      • Патчинг
      • Start iOS Debug Server
      • iOS Audio Framework
      • Facebook SDK
      • Swift
      • Attack Secure Boot of SEP
      • iOS Kernel Firmware
    • Tools
      • frida
        • Установка
        • Frida CLI
        • Запуск скриптов
        • Общие команды (JS API)
        • Frida Projects
        • Примеры
          • Материалы
          • Android
          • iOS
          • Unity/Mono
          • Общее
            • Вывод Callstack
            • Перехват инструкции по смещению
            • Перехват функции по имени
            • Перехват функции по смещению (sub_*)
      • objection
      • luject
      • emulators
    • Кейсы
      • Hybrid App
        • Intro
        • Hermes
        • Xamarin
        • React Native
        • Unity
        • Debug Hybrid App
    • Статьи
  • Administration
    • Инструменты
      • Android
        • uiautomatorviewer
        • jobb
        • archquery
        • apkanalyzer
        • avdmanager
        • emulator
        • perfetto
        • monkeyrunner
        • Настройка окружения
        • sdkmanager
Powered by GitBook
On this page
  • С точки зрения разработки
  • Подключение в проект
  • Структура
  • Как пользоваться
  • UI поток

Was this helpful?

  1. Programming
  2. Android
  3. Frameworks

Room

PreviousWorkManagerNextData binding

Last updated 5 years ago

Was this helpful?

Room - обертка над SQLIte/Realm/DAO, представленная на Goolge I/O. Room provides an abstraction layer over SQLite in a similar way to Retrofit with network requests. Пример использования: androidx.room.

Выглядит как достаточно безопасная штука, которая переводит объекты сразу в базу и обратно. Если делать все по инструкции, ошибиться невозможно (про sqli) Подробно:

Две норм статьи по разработке с помощью Room:

С точки зрения разработки

Поэтапное создание

Подключение в проект

В build.gradle файл проекта добавьте репозитарий google()

allprojects {
    repositories {
        jcenter()
        google()
    }
    ...
}

В build.gradle файле модуля добавьте dependencies:

dependencies {
    implementation "android.arch.persistence.room:runtime:1.0.0"
    annotationProcessor "android.arch.persistence.room:compiler:1.0.0"
    ...
}

Структура

Три основных компонента - Entity, Dao, Database Entity - объект, который хотим хранить в базе. Используется для создания таблицы. Database - Dao - описывает методы для работы с базой данных.

Entity

@Entity
public class Employee {

   @PrimaryKey
   public long id;

   public String name;

   public int salary;
}

По умолчанию, имя создаваемой таблицы будет название класса. Следующим образом задается свое название таблицы:

@Entity(tableName = "employees")
public class Employee {
   // ...
}

Переопределить имя поля:

@Entity()
public class Employee {
   @PrimaryKey()
   public long id;

   @ColumnInfo(name = "full_name")
   public String fullName;
   public int salary;
}

По умолчанию Room определяет тип данных для поля в таблице по типу данных поля в Entity классе. Но мы можем явно указать свой тип.

@Entity()
public class Employee {

   @PrimaryKey(autoGenerate = true)
   public long id;
   public String name;

   @ColumnInfo(typeAffinity = TEXT)
   public int salary;
}

У PrimaryKey есть параметр autoGenerate. Он позволяет включить для поля режим autoincrement, в котором база данных сама будет генерировать значение, если вы его не укажете.

Чтобы создать составной ключ, используйте параметр primaryKeys.

@Entity(primaryKeys = {"key1", "key2"})
public class Item {
   public long key1;
   public long key2;
   // ...
}

Внешний ключ (ForeignKeys) Внешние ключи позволяют связывать таблицы между собой. Если вы еще не знакомы с ними, то можете почитать о них в инете. В выше рассмотренных примерах у нас есть класс Employee для хранения данных по сотрудникам. Давайте создадим класс Car для хранения данных по машинам. И каждая машина должна быть прикреплена к какому-либо сотруднику.

Важно: When we use foreign key dont forget to put onDelete = ForeignKey.CASCADE this way if you delete an data it will also delete de dependency. This way you won't have false data or data that are never use

@Entity(foreignKeys = @ForeignKey(entity = Employee.class, parentColumns = "id", childColumns = "employee_id"))
public class Car {

   @PrimaryKey(autoGenerate = true)
   public long id;
   public String model;
   public int year;

   @ColumnInfo(name = "employee_id")
   public long employeeId;
}

Индекс (Index) Индексы могут повысить производительность вашей таблицы. Если вы еще не знакомы с ними, то можете почитать о них в инете. В аннотации Entity есть параметр indicies, который позволяет задавать индексы.

@Entity(indices = {
               @Index("salary"),
               @Index(value = {"first_name", "last_name"})
           }
       )
public class Employee {
   @PrimaryKey(autoGenerate = true)
   public long id;

   @ColumnInfo(name = "first_name")
   public String firstName;

   @ColumnInfo(name = "last_name")
   public String lastName;
   public int salary;
}

Создаем два индекса: один по полю salary, а другой по двум полям first_name и last_name.

Индекс для одного поля также может быть настроен через параметр index аннотации ColumnInfo

@Entity()
public class Employee {

   @PrimaryKey(autoGenerate = true)
   public long id;
   public String name;

   @ColumnInfo(index = true)
   public int salary;
}

Будет создан индекс для поле salary.

Вложенные объекты Пусть у нас есть класс Address, с данными о адресе. Это обычный класс, не Entity.

public class Address {
   public String city;
   public String street;
   public int number;
}

И мы хотим использовать его в Entity классе Employee

@Entity()
public class Employee {
   @PrimaryKey(autoGenerate = true)
   public long id;
   public String name;
   public int salary;
   @Embedded
   public Address address;
}

Простое решение - использовать аннотацию Embedded. Если у вас получается так, что совпадают имена каких-то полей в основном объекте и в Embedded объекте, то используйте префикс для Embedded объекта.

@Embedded(prefix = "address")
public Address address;

В этом случае к именам полей Embedded объекта в таблице будет добавлен указанный префикс.

Ignore Аннотация Ignore позволяет подсказать Room, что это поле не должно записываться в базу или читаться из нее.

@Entity
public class Employee {
   @PrimaryKey
   public long id;

   public String name;
   public int salary;

   @Ignore
   public Bitmap avatar;
}

Dao

Обратите внимание, что в качестве имени таблицы мы используем employee. Напомню, что имя таблицы равно имени Entity класса, т.е. Employee, но в SQLite не важен регистр в именах таблиц, поэтому можем писать employee. Для вставки/обновления/удаления используются методы insert/update/delete с соответствующими аннотациями. Тут никакие запросы указывать не нужно. Названия методов могут быть любыми. Главное - аннотации.

@Dao
public interface EmployeeDao {

   @Query("SELECT * FROM employee")
   List<Employee> getAll();

   @Query("SELECT * FROM employee WHERE id = :id")
   Employee getById(long id);

   @Insert
   void insert(Employee employee);

   @Update
   void update(Employee employee);

   @Delete
   void delete(Employee employee);

}

Database

Аннотацией Database помечаем основной класс по работе с базой данных. Этот класс должен быть абстрактным и наследовать RoomDatabase.

@Database(entities = {Employee.class}, version = 1)
public abstract class AppDatabase extends RoomDatabase {
   public abstract EmployeeDao employeeDao();
}

В параметрах аннотации Database указываем, какие Entity будут использоваться, и версию базы. Для каждого Entity класса из списка entities будет создана таблица.

В Database классе необходимо описать абстрактные методы для получения Dao объектов, которые вам понадобятся.

Как пользоваться

Database объект - это стартовая точка. Его создание выглядит так:

AppDatabase db =  Room.databaseBuilder(getApplicationContext(),
       AppDatabase.class, "database").build();

Используем Application Context, а также указываем AppDatabase класс и имя файла для базы.

Учитывайте, что при вызове этого кода Room каждый раз будет создавать новый экземпляр AppDatabase. Эти экземпляры очень тяжелые и рекомендуется использовать один экземпляр для всех ваших операций. Поэтому вам необходимо позаботиться о синглтоне для этого объекта. Это можно сделать с помощью Dagger, например.

Если вы не используете Dagger (или другой DI механизм), то можно использовать Application класс для создания и хранения AppDatabase:

public class App extends Application {

    public static App instance;

    private AppDatabase database;

    @Override
    public void onCreate() {
        super.onCreate();
        instance = this;
        database = Room.databaseBuilder(this, AppDatabase.class, "database")
                .build();
    }

    public static App getInstance() {
        return instance;
    }

    public AppDatabase getDatabase() {
        return database;
    }
}

Не забудьте добавить App класс в манифест

В коде получение базы будет выглядеть так:

AppDatabase db = App.getInstance().getDatabase();

Из Database объекта получаем Dao.

EmployeeDao employeeDao = db.employeeDao();

Теперь мы можем работать с Employee объектами. Но эти операции должны выполняться не в UI потоке. Иначе мы получим Exception.

Добавление нового сотрудника в базу будет выглядеть так:

Employee employee = new Employee();
employee.id = 1;
employee.name = "John Smith";
employee.salary = 10000;

employeeDao.insert(employee);

Метод getAll вернет нам всех сотрудников в List

List<Employee> employees = employeeDao.getAll();

Получение сотрудника по id:

Employee employee = employeeDao.getById(1);

UI поток

Операции по работе с базой данных - синхронные, и должны выполняться не в UI потоке.

В случае с Query операциями мы можем сделать их асинхронными используя LiveData или RxJava.

https://habr.com/ru/post/336196/
https://developer.android.com/training/data-storage/room/accessing-data
https://medium.com/@appmattus/android-security-sql-injection-with-the-room-persistence-library-69f4e286960f
https://medium.com/androiddevelopers/7-steps-to-room-27a5fe5f99b2
https://medium.com/androiddevelopers/7-pro-tips-for-room-fbadea4bfbd1
https://codelabs.developers.google.com/codelabs/android-room-with-a-view-kotlin/#4