Как быстро получать данные из ОС Аврора через интерфейс D-Bus во Flutter-приложении

Привет, Хабр! Меня зовут Юрий Петров, я автор ютуб-канала «Мобильный разработчик» и Flutter Tech Lead в компании Friflex. Мы разрабатываем мобильные приложения для бизнеса и специализируемся на Flutter. 

В этой статье я расскажу, как с помощью интерфейса D-Bus можно быстро получить необходимую вам информацию из системы Аврора.

e08c4a9b24a3e66194246d0a29a3a2fe.jpg

Что такое интерфейс D-Bus

D-Bus — как почтальон, доставляет сообщения от одного процесса к другому в unix-системах. С помощью D-Bus мы можем обратиться к конкретной службе в системе и получить необходимую информацию. 

На схеме изображена работа D-Bus.

cbda79ee3a4a67f16777e41bacf026c0.png

У Авроры, как у unix-системы, есть открытые интерфейсы D-Bus. Познакомиться с ними можно по ссылке.

  1. ru.omp.deviceinfo.Features дает информацию об основных параметрах и функциях устройства: версии ОС, модели, разрешении экрана, данных о ЦП, ОЗУ и камере, наличии модулей связи.

  2. ru.omp.deviceinfo.SIM предоставляет данные о SIM-карте и позволяет отслеживать события, связанные с ней.

  3. ru.omp.deviceinfo.Storages дает доступ к информации о памяти на устройстве: флэш-памяти, внешнем хранилище, разделах пользователей.

Есть и другие интерфейсы. Я покажу, как их можно получать напрямую из системы. Для примера, попробуем получить из ОС Аврора информацию о заряде батареи смартфона.

Получаем информацию о заряде батареи

Создаем Flutter-проект с названием flutter_dbus. Добавляем поддержку системы Аврора в проект командой:

flutter create --platforms=aurora --org=com.example .

Если не знаете, как начать писать для системы Авроры на Flutter, можно посмотреть мои обучающие видео на Youtube или почитать статьи ОМП на Хабре.

Переходим в появившуюся папку aurora, далее в папку desktop и в файл com.example.flutter_dbus.desktop.

В разделе [X-Application] разрешите читать данные об устройстве Permissions=DeviceInfo:

[Desktop Entry]
Type=Application
Name=flutter_dbus
Comment=A new Flutter project.
Icon=com.example.flutter_dbus
Exec=/usr/bin/com.example.flutter_dbus
X-Nemo-Application-Type=silica-qt5

[X-Application]
Permissions=DeviceInfo
OrganizationName=com.example
ApplicationName=flutter_dbus

После этого нам нужно установить глобально специальный пакет для работы с D-Bus на языке Dart.

Вызываем команду:

dart pub global activate dbus

И добавляем в pubspec.yaml данный пакет:

dependencies:
  dbus: ^0.7.10

Пакет D-bus очень простой. Описываем интерфейс в файле .xml, и пакет создает готовый код для работы с интерфейсом.

Создаем файл data.xml в корне проекта. В нем описываем интерфейс ru.omp.deviceinfo.Features.


   
   

В теле интерфейса указываем метод получения заряда батареи. Список доступных методов можно изучить на странице интерфейса.


   
       
       
   

a4ce07ef776b9f60b3ede27ab9cc9005.png

Важно указать правильный тип возвращаемого значения. Мы видим, что метод getBatteryChargePercentage(uint &chargePercentage) возвращает целочисленное значение типа integer.


   
       
           
       
   

В аргументах описания метода указываем, что он вернет целое число. Теперь генерируем код при помощи команды:

dart-dbus generate-remote-object data.xml -o lib/data.dart

После генерации в папке lib data.dart появляется файл:

// This file was generated using the following command and may be overwritten.
// dart-dbus generate-remote-object data.xml


import 'dart:io';
import 'package:dbus/dbus.dart';


class RuOmpDeviceinfoFeatures extends DBusRemoteObject {
 RuOmpDeviceinfoFeatures(DBusClient client, String destination, DBusObjectPath path) : super(client, name: destination, path: path);


 /// Invokes ru.omp.deviceinfo.Features.getBatteryChargePercentage()
 Future callgetBatteryChargePercentage({bool noAutoStart = false, bool allowInteractiveAuthorization = false}) async {
   var result = await callMethod('ru.omp.deviceinfo.Features', 'getBatteryChargePercentage', [], replySignature: DBusSignature('u'), noAutoStart: noAutoStart, allowInteractiveAuthorization: allowInteractiveAuthorization);
   return result.returnValues[0].asUint32();
 }
}

В файле находится код, с помощью которого можно запросить из системы данные о заряде батареи.

Осталось добавить в проект следующий код:

Создаем запрос в платформу

Создаем клиента:

final client = DBusClient.session(); 

Создаем объект для работы с интерфейсом D-Bus:

 final features = RuOmpDeviceinfoFeatures(
   client,
   'ru.omp.deviceinfo',
   DBusObjectPath('/ru/omp/deviceinfo/Features'),
 );

Получаем заряд батареи из системы:

final percent = await features.callgetBatteryChargePercentage();

Отображаем в MaterialApp:

 runApp(MaterialApp(
     home: Scaffold(
         body: Center(
   child: Text(
     percent.toString(),
   ),
 ))));

При запуске проекта в системе получаем отображение заряда батареи:

Результат

b70e85184145b260dc18fbc7f9b61638.png

Получаем список всех интерфейсов D-Bus

Как и обещал, рассказываю, как получить список всех интерфейсов D-Bus. Подключаемся к смартфону через ssh, и вводим команду списка интерфейсов в этой сессии:

dbus-send --session           \
  --dest=org.freedesktop.DBus \
  --type=method_call          \
  --print-reply               \
  /org/freedesktop/DBus       \
  org.freedesktop.DBus.ListNames.

В терминале отобразится список всех поддерживаемых интерфейсов D-Bus. По-другому получить этот список можно при помощи команды:

dbus-send --system            \
   --dest=org.freedesktop.DBus \
   --type=method_call          \
   --print-reply               \
   /org/freedesktop/DBus       \
   org.freedesktop.DBus.ListNames

Этот запрос вернет все доступные системные интерфейсы D-Bus. Чтобы их изучить, достаточно просто написать название в любом поисковике.

Если у вас что-то не получилось, можно клонировать проект из гитхаба.

Надеюсь, статья будет вам полезна. С удовольствием отвечу на вопросы в комментариях.

© Habrahabr.ru