Majid Hajian
mhadaily
Majid Hajian
mhadaily
if (Platform.isIOS) {
//
}
if (Platform.isAndroid) {
//
}
if (Platform.isLinux) {
//
}
if (Platform.isMacOS) {
//
}
if (Platform.isWindows) {
//
}
if (kIsWeb) {
//
}
mhadaily
mhadaily
mhadaily
import 'package:flutter/material.dart';
MaterialApp(
ThemeData(
name: "Majid Hajian",
location: "Oslo, Norway",
description: '''
Google Developer Expert
Passionate Software engineer,
Community Leader, Author and international Speaker
''',
main: "Head of DevRel at Invertase.io",
homepage: "https://www.majidhajian.com",
socials: {
twitter: "https://www.twitter.com/mhadaily",
github: "https://www.github.com/mhadaily"
},
author: {
Pluralsight: "www.pluralsight.com/authors/majid-hajian",
Apress: "Progressive Web App with Angular, Book",
PacktPub: "PWA development",
Udemy: "PWA development",
}
founder: "Softiware As (www.Softiware.com)"
devDependencies: {
tea: "Ginger",
mac: "10.14+",
},
community: {
MobileEraConference: "Orginizer",
FlutterVikings: "Orginizer",
FlutterDartOslo: "Orginizer",
GDGOslo: "Co-Orginizer",
DevFestNorway: "Orginizer",
...more
}));
Find me on the internet by
Head of DevRel at Invertase
mhadaily
mhadaily
Platform-specific code for the web generally uses JS interoperability or the dart:html library instead.
mhadaily
import 'dart:async';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
class _MyHomePageState extends State<MyHomePage> {
static const platform = MethodChannel('plus.fluttercommunity.dev/battery');
String _batteryLevel = 'Unknown battery level.';
Future<void> _getBatteryLevel() async {
String batteryLevel;
try {
final int result = await platform.invokeMethod('getBatteryLevel');
batteryLevel = 'Battery level at $result % .';
} on PlatformException catch (e) {
batteryLevel = "Failed to get battery level: '${e.message}'.";
}
setState(() {
_batteryLevel = batteryLevel;
});
}
}
mhadaily
// MainActivity.kt
import androidx.annotation.NonNull
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
import io.flutter.plugin.common.MethodChannel
class MainActivity: FlutterActivity() {
private val CHANNEL = "plus.fluttercommunity.dev/battery"
override fun configureFlutterEngine(@NonNull flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
MethodChannel(flutterEngine.dartExecutor.binaryMessenger, CHANNEL).setMethodCallHandler {
call, result ->
if (call.method == "getBatteryLevel") {
val batteryLevel = getBatteryLevel()
if (batteryLevel != -1) {
result.success(batteryLevel)
} else {
result.error("UNAVAILABLE", "Battery level not available.", null)
}
} else {
result.notImplemented()
}
}
}
}
mhadaily
typedef flutter::MethodChannel<flutter::EncodableValue> FlMethodChannel;
typedef flutter::EventChannel<flutter::EncodableValue> FlEventChannel;
BatteryPlusWindowsPlugin::BatteryPlusWindowsPlugin(
flutter::PluginRegistrarWindows *registrar) {
auto methodChannel = std::make_unique<FlMethodChannel>(
registrar->messenger(), "dev.fluttercommunity.plus/battery",
&flutter::StandardMethodCodec::GetInstance());
methodChannel->SetMethodCallHandler([this](const auto &call, auto result) {
HandleMethodCall(call, std::move(result));
});
auto eventChannel = std::make_unique<FlEventChannel>(
registrar->messenger(), "dev.fluttercommunity.plus/charging",
&flutter::StandardMethodCodec::GetInstance());
eventChannel->SetStreamHandler(
std::make_unique<BatteryStatusStreamHandler>(registrar));
}
mhadaily
void BatteryPlusWindowsPlugin::HandleMethodCall(
const FlMethodCall &method_call, std::unique_ptr<FlMethodResult> result) {
if (method_call.method_name().compare("isInBatterySaveMode") == 0) {
SystemBattery battery;
int batteryStatus = battery.GetBatterySaveMode();
if (batteryStatus == 0 || batteryStatus == 1) {
bool isBatteryMode = batteryStatus == 1;
result->Success(flutter::EncodableValue(isBatteryMode));
} else {
result->Error(std::to_string(battery.GetError()),
battery.GetErrorString());
}
} else if (method_call.method_name().compare("getBatteryLevel") == 0) {
SystemBattery battery;
int level = battery.GetLevel();
if (level >= 0) {
result->Success(flutter::EncodableValue(level));
} else {
result->Error(std::to_string(battery.GetError()),
battery.GetErrorString());
}
} else if (method_call.method_name().compare("getBatteryState") == 0) {
SystemBattery battery;
result->Success(flutter::EncodableValue(battery.GetStatusString()));
} else {
result->NotImplemented();
}
}
mhadaily
https://api.flutter.dev/flutter/services/StandardMessageCodec-class.html
https://docs.flutter.dev/development/platform-integration/platform-channels
mhadaily
Pigeon
mhadaily
mhadaily
https://pub.dev/packages/pigeon
class Value {
int? number;
}
@HostApi()
abstract class Api2Host {
@async
Value calculate(Value value);
}
// Objc
@protocol Api2Host
-(void)calculate:(nullable Value *)input
completion:(void(^)(Value *_Nullable, FlutterError *_Nullable))completion;
@end
// ----
// Java
public interface Result<T> {
void success(T result);
}
/** Generated interface from Pigeon that represents a handler of messages from Flutter.*/
public interface Api2Host {
void calculate(Value arg, Result<Value> result);
}
// ----
// C++
/** Generated class from Pigeon that represents a handler of messages from Flutter.*/
class Api2Host {
public:
virtual void calculate(Value value, flutter::MessageReply<Value> result) = 0;
}
mhadaily
mhadaily
Plugins
mhadaily
name: battery_plus_example
description: Demonstrates how to use the battery_plus plugin.
environment:
sdk: '>=2.12.0 <3.0.0'
dependencies:
flutter:
sdk: flutter
battery_plus:
dev_dependencies:
flutter_driver:
sdk: flutter
integration_test:
sdk: flutter
flutter_lints: ^1.0.4
flutter:
uses-material-design: true
https://plus.fluttercommunity.dev/
mhadaily
https://firebase.flutter.dev/
mhadaily
mhadaily
A federated plugin requires:
https://medium.com/flutter/modern-flutter-plugin-development-4c3ee015cf5a
mhadaily
flutter create --template=plugin --platforms=linux battery_plus_linux
--platforms=android, ios, web, linux, macos, windows.
flutter create --template=package battery_plus_platform_interface
mhadaily
Endorsed Plugins vs Non-endorsed
// Pubspec.yaml
flutter:
plugin:
platforms:
android:
package: dev.fluttercommunity.battery_plus
pluginClass: BatteryPlusPlugin
ios:
pluginClass: BatteryPlusPlugin
macos:
pluginClass: BatteryPlusPlugin
web:
pluginClass: BatteryPlusPlugin
fileName: battery_plus_web.dart
mhadaily
// pubspec.yaml
flutter:
plugin:
platforms:
android:
package: dev.fluttercommunity.plus.battery
pluginClass: BatteryPlusPlugin
ios:
pluginClass: FLTBatteryPlusPlugin
linux:
default_package: battery_plus_linux
macos:
default_package: battery_plus_macos
web:
default_package: battery_plus_web
windows:
default_package: battery_plus_windows
dependencies:
flutter:
sdk: flutter
meta: ^1.7.0
battery_plus_platform_interface: ^1.2.0
battery_plus_linux: ^1.1.0
battery_plus_macos: ^1.1.0
battery_plus_web: ^1.1.0
battery_plus_windows: ^1.1.0
mhadaily
// batter_plus_linux/pubspec.yaml
flutter:
plugin:
implements: battery_plus
platforms:
linux:
dartPluginClass: BatteryPlusLinux
pluginClass: none
dependencies:
flutter:
sdk: flutter
battery_plus_platform_interface: ^1.2.0
dbus: ^0.6.6
meta: ^1.7.0
mhadaily
// batter_plus_web/pubspec.yaml
flutter:
plugin:
platforms:
web:
pluginClass: BatteryPlusPlugin
fileName: battery_plus_web.dart
dependencies:
battery_plus_platform_interface: ^1.2.0
flutter_web_plugins:
sdk: flutter
flutter:
sdk: flutter
mhadaily
import 'dart:async';
import 'package:plugin_platform_interface/plugin_platform_interface.dart';
import 'method_channel_battery_plus.dart';
import 'src/enums.dart';
abstract class BatteryPlatform extends PlatformInterface {
BatteryPlatform() : super(token: _token);
static final Object _token = Object();
static BatteryPlatform _instance = MethodChannelBattery();
static BatteryPlatform get instance => _instance;
static set instance(BatteryPlatform instance) {
PlatformInterface.verifyToken(instance, _token);
_instance = instance;
}
Future<int> get batteryLevel {
throw UnimplementedError('batteryLevel() has not been implemented.');
}
Future<bool> get isInBatterySaveMode {
throw UnimplementedError('isInBatterySaveMode() has not been implemented.');
}
Future<BatteryState> get batteryState {
throw UnimplementedError('batteryState() has not been implemented.');
}
Stream<BatteryState> get onBatteryStateChanged {
throw UnimplementedError(
'get onBatteryStateChanged has not been implemented.');
}
}
mhadaily
class MethodChannelBattery extends BatteryPlatform {
@visibleForTesting
MethodChannel methodChannel =
const MethodChannel('dev.fluttercommunity.plus/battery');
@visibleForTesting
EventChannel eventChannel =
const EventChannel('dev.fluttercommunity.plus/charging');
Stream<BatteryState>? _onBatteryStateChanged;
@override
Future<int> get batteryLevel => methodChannel
.invokeMethod<int>('getBatteryLevel')
.then<int>((dynamic result) => result);
@override
Future<bool> get isInBatterySaveMode => methodChannel
.invokeMethod<bool>('isInBatterySaveMode')
.then<bool>((dynamic result) => result);
@override
Future<BatteryState> get batteryState => methodChannel
.invokeMethod<String>('getBatteryState')
.then<BatteryState>((dynamic result) => parseBatteryState(result));
@override
Stream<BatteryState> get onBatteryStateChanged {
_onBatteryStateChanged ??= eventChannel
.receiveBroadcastStream()
.map((dynamic event) => parseBatteryState(event));
return _onBatteryStateChanged!;
}
}
mhadaily
import 'dart:async';
import 'package:battery_plus_platform_interface/battery_plus_platform_interface.dart';
export 'package:battery_plus_platform_interface/battery_plus_platform_interface.dart'
show BatteryState;
class Battery {
factory Battery() {
_singleton ??= Battery._();
return _singleton!;
}
Battery._();
static Battery? _singleton;
static BatteryPlatform get _platform {
return BatteryPlatform.instance;
}
Future<int> get batteryLevel {
return _platform.batteryLevel;
}
Future<bool> get isInBatterySaveMode {
return _platform.isInBatterySaveMode;
}
Future<BatteryState> get batteryState {
return _platform.batteryState;
}
Stream<BatteryState> get onBatteryStateChanged {
return _platform.onBatteryStateChanged;
}
}
mhadaily
// battery_plus_web/lib/battery_plus_web.dart
import 'dart:async';
import 'dart:html' as html show window, BatteryManager, Navigator;
import 'package:battery_plus_platform_interface/battery_plus_platform_interface.dart';
import 'package:flutter_web_plugins/flutter_web_plugins.dart';
class BatteryPlusPlugin extends BatteryPlatform {
BatteryPlusPlugin(html.Navigator navigator)
: _getBattery = navigator.getBattery;
bool get isSupported => html.window.navigator.getBattery != null;
late final Future<dynamic> Function() _getBattery;
static void registerWith(Registrar registrar) {
BatteryPlatform.instance = BatteryPlusPlugin(html.window.navigator);
}
@override
Future<int> get batteryLevel async {
if (isSupported) {
// level is a number representing the system's battery charge level scaled to a value between 0.0 and 1.0
final batteryManager = await _getBattery() as html.BatteryManager;
final level = batteryManager.level ?? 0;
return level * 100 as int;
}
return 0;
}
}
mhadaily
Phew!
mhadaily
mhadaily
mhadaily
melos.invertase.dev
mhadaily
mhadaily
mhadaily
mhadaily
mhadaily
mhadaily
mhadaily
Majid Hajian
find me on internet
mhadaily
Slides and link to source code
slides.com/mhadaily