Run native code when triggering alarms with flutter - flutter

I have an example that implements an example of Android Alarm Manager with flutter, the event is called normal, however, I want that when the alarm goes off, a native code (Java or Kt) is executed.
Example:
As soon as the alarm goes off even in the background or locked screen, the app will execute my code in Java.
In native Java we created a class that inherits from BroadcastReceiver and implements the onReceive method, in Android Native I would open my app even in the background with native code.
How can I get the flutter to call my native code to run when the alarm is triggered?
My code example:
import 'package:flutter/material.dart';
import 'package:android_alarm_manager/android_alarm_manager.dart';
import 'package:android_intent/android_intent.dart';
import 'package:android_intent/flag.dart';
import 'package:platform/platform.dart';
void main() async {
WidgetsFlutterBinding.ensureInitialized();
await AndroidAlarmManager.initialize();
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Alarme app',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Alarme'),
debugShowCheckedModeBanner: false,
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
void _openLinkInGoogleChrome() {
print('entered');
if (const LocalPlatform().isAndroid) {
// **run Native code java here that implemented onReceive on class .java or .kt !!!**
}
}
class _MyHomePageState extends State<MyHomePage> {
void adicionarAlarme(BuildContext context) async {
await AndroidAlarmManager.periodic(
const Duration(seconds: 3), 0, _openLinkInGoogleChrome);
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Clique no botão abaixo para adicionar um alarme',
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () => adicionarAlarme(context),
tooltip: 'Adicionar alarme',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}

Related

Flutter mocked clock (using withClock) behave inconsistenly when app starts with WidgetsFlutterBinding.ensureInitialized()

If flutter app starts with:
void main() {
WidgetsFlutterBinding.ensureInitialized();
Then clock.now() prints not mocked value if outside of build method.
Since I am using withClock in my tests, it makes my app unable to be properly tested as sometimes clock.now() returns mocked value, and sometimes real current time.
Please find the following example, and note that _printClockNow prints DateTime.now(), but it should print year 1990.
If you removed line WidgetsFlutterBinding.ensureInitialized() then it works as expected.
Minimum reproduceable code:
import 'package:clock/clock.dart';
import 'package:flutter/material.dart';
void main() {
WidgetsFlutterBinding.ensureInitialized();
withClock(Clock.fixed(DateTime(1990)), () {
runApp(const MyApp());
});
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
void _printClockNow() {
print('_printClockNow is: ${clock.now()}'); // prints real NOW
setState(() {});
}
#override
Widget build(BuildContext context) {
print('build clock.now() is: ${clock.now()}'); // prints mocked NOW
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[Dummy()],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _printClockNow,
tooltip: 'Increment',
child: const Icon(Icons.add),
),
);
}
}
class Dummy extends StatelessWidget {
#override
Widget build(Object context) {
return Text('t: ${clock.now()}');
}
}
Try with putting WidgetsFlutterBinding inside withClock.
void main() {
withClock(Clock.fixed(DateTime(1990)), () {
WidgetsFlutterBinding.ensureInitialized();
runApp(const MyApp());
});
}

How to write test for flutter package Flutter WeChat Assets Picker

I am trying to write a test on this flutter package https://pub.dev/packages/wechat_assets_picker using the Mocktail package https://pub.dev/packages/mocktail, but this package does not seem to have test in the documentation.
I have included the minimum reproducible example. The test file is currently not working, it is included as an example test code using the flutter Mocktail package.
It is supposed to mock AssetPicker.pickAssets to test whether it is actually called with the correct arguments. I am running in IOS simulator, we will need to add this key in ios/Runer/Info.plist, otherwise the simulator will close unexpectedly after clicking the add button.
main.dart
import 'package:flutter/material.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
void main() {
runApp(const MyApp());
}
class MyApp extends StatelessWidget {
const MyApp({Key? key}) : super(key: key);
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({Key? key, required this.title}) : super(key: key);
final String title;
#override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: const [],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () async {
final List<AssetEntity>? result =
await AssetPicker.pickAssets(context);
},
tooltip: 'Add photo',
child: const Icon(Icons.add),
),
);
}
}
widget_test.dart
import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:mocktail/mocktail.dart';
import 'package:wechat/main.dart';
import 'package:wechat_assets_picker/wechat_assets_picker.dart';
class _MockAssetPicker extends Mock implements AssetPicker {}
void main() {
testWidgets('It should call the WeChat asset picker',
(WidgetTester tester) async {
await tester.pumpWidget(const MyApp());
final BuildContext context = tester.element(find.byType(MyApp));
final assetPickerMock = _MockAssetPicker();
when(() => assetPickerMock.pickAssets(context)).thenAnswer((_) => Future.value([
const AssetEntity(
id: 'id1',
typeInt: 1,
width: 100,
height: 100,
),
]));
AssetPicker.instance = assetPickerMock;
await tester.tap(find.byIcon(Icons.add));
await tester.pump();
verify(() => assetPickerMock.pickAssets(context)).called(1);
});
}
Mocking the picker is supported by the separated picker delegate: https://github.com/fluttercandies/flutter_wechat_assets_picker/pull/315
TL;DR, build your own delegate first, then set it through AssetPicker.setPickerDelegate(TestAssetPickerDelegate());

Geolocation.getCurrentPosition from dart:html not working in release mode with NNBD enabled

Does anybody know why the Geolocation.getCurrentPosition() from dart:html doesn't work when running in release mode with sound null safety enabled (flutter run --release -d chrome)?
When making this call I do get an instance of Geoposition back but when I try to access one of it's members I get the following error message:
Uncaught TypeError: n.grq is not a function
at main.dart:39
at WD.a (async_patch.dart:316)
at WD.$2 (async_patch.dart:341)
at VR.$1 (async_patch.dart:292)
at UG.SB (zone.dart:1612)
at UG.ug (zone.dart:1611)
at Tf.$0 (future_impl.dart:118)
at Object.n3 (future_impl.dart:733)
at Y.ib (future_impl.dart:539)
at T7.$0 (future_impl.dart:577)
If I run the same code in debug (flutter run -d chrome or without NNBD flutter run -d chrome --release --no-sound-null-safety everything works fine). A simple App that reproduces this behaviour looks like this (it's a slightly changed version of the default Flutter counter template):
import 'dart:html' as html;
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key? key, this.title}) : super(key: key);
final String? title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
String _position = "Unknown";
Future<void> _currentPosition() async {
final geolocation = html.window.navigator.geolocation;
final position = await geolocation.getCurrentPosition();
final latitude = position.coords?.latitude ?? 'n/a';
final longitude = position.coords?.longitude ?? 'n/a';
setState(() {
_position =
'Latitude: $latitude, Longitude: $longitude';
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title!),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'Your current position is:',
),
Text(
'$_position',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _currentPosition,
tooltip: 'Current position',
child: Icon(Icons.location_on),
),
);
}
}
This turns out to be a bug in Dart. I have created a bug report which can be tracked here: https://github.com/dart-lang/sdk/issues/45562

Need assistance with Providers in Flutter

I'm trying to get my head around the Providers in Flutters... but after following some tutorials, I'm still facing some issue.
When I try to run this code, it gives me an error
Error: Could not find the correct Provider above this MyHomePage Widget
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_way/MyHomePageViewModel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (context) => MyHomePageViewModel(),
child: Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Consumer<MyHomePageViewModel>(
builder: (context, viewModel, child) {
return Text(viewModel.text);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () =>
Provider.of<MyHomePageViewModel>(context, listen: false)
.onClicked(),
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
),
);
}
}
import 'package:flutter/foundation.dart';
class MyHomePageViewModel extends ChangeNotifier {
String text = 'Initial text';
void onClicked() {
text = 'Something was clicked';
notifyListeners();
}
}
The website where I found this example use it as
Provider.of<MainViewModel>(context, listen: false).onClicked(),
But that doesn't work either...
Before a widget that needs a provider is presented, it is required you create that particular provider before the page is built.
Checkout the working sample of your code below.
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';
import 'package:provider_way/MyHomePageViewModel.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return ChangeNotifierProvider(
create: (_) => MyHomePageViewModel(),
builder: (_, __) => MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Consumer<MyHomePageViewModel>(
builder: (context, viewModel, child) {
return Text(viewModel.text);
},
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: () =>
Provider.of<MyHomePageViewModel>(context, listen: false)
.onClicked(),
tooltip: 'Increment',
child: Icon(Icons.add),
), // This trailing comma makes auto-formatting nicer for build methods.
);
}
}
import 'package:flutter/foundation.dart';
class MyHomePageViewModel extends ChangeNotifier {
String text = 'Initial text';
void onClicked() {
text = 'Something was clicked';
notifyListeners();
}
}
In your provider code, do you have a class defined like:
class MyHomePageViewModel extends ChangeNotifier {
// your stuff here, like getter and setters, methods, etc
}
That class will deal with all the centralisation of your states, essentially acting as you'd hope - the provider.

Flutter: How to change the state of a variable in another dart file?

I am currently working on an app; I want to change the value of a String which is declared in another dart file and then pass that changed state to the stateful widget.
I.E;
I create a file called as "Body.dart" file where I have declared a String called as 'scale' who's value initially is "Empty".
Later when a button in another dart file "scale_button" is pressed, I want to assign the string scale = "Hello" in my Body.dart file. So that the stateful widget also displays the same on the screen.
You can use provider(or any other state management) package in that case. In yaml file add, provider: ^4.3.2+4
class HomeApp extends StatefulWidget {
#override
_HomeAppState createState() => _HomeAppState();
}
class _HomeAppState extends State<HomeApp> {
StringProvider _stringProvider;
#override
void initState() {
super.initState();
_stringProvider = Provider.of<StringProvider>(context, listen: false);
}
void updateString() {
_stringProvider.setString('hai');
}
#override
Widget build(BuildContext context) {
StringProvider _stringProvider = Provider.of<StringProvider>(context);
return Scaffold(
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
Container(
child: Text(
_stringProvider.str,
style: TextStyle(
fontSize: 22,
),
),
),
RaisedButton(
onPressed: updateString,
child: Text('Click'),
),
],
),
),
);
}
}
// class for storing data(StringProvider.dart)
import 'package:flutter/material.dart';
class StringProvider extends ChangeNotifier { // create a common file for data
String _str = 'hello';
String get str => _str;
void setString(String st) {
_str = st;
notifyListeners();
}
}
When you create a new Flutter project the sample code of the counter shows you how to do this. Check out the comments in the next code:
class MyApp extends StatelessWidget {
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
// here is passing a String to MyHomePage.
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
// And here you can see how to make the widget wait for a variable
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
Full code of Sample Counter App
import 'package:flutter/material.dart';
void main() {
runApp(MyApp());
}
class MyApp extends StatelessWidget {
// This widget is the root of your application.
#override
Widget build(BuildContext context) {
return MaterialApp(
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: MyHomePage(title: 'Flutter Demo Home Page'),
);
}
}
class MyHomePage extends StatefulWidget {
MyHomePage({Key key, this.title}) : super(key: key);
final String title;
#override
_MyHomePageState createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
int _counter = 0;
void _incrementCounter() {
setState(() {
_counter++;
});
}
#override
Widget build(BuildContext context) {
return Scaffold(
appBar: AppBar(
title: Text(widget.title),
),
body: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: <Widget>[
Text(
'You have pushed the button this many times:',
),
Text(
'$_counter',
style: Theme.of(context).textTheme.headline4,
),
],
),
),
floatingActionButton: FloatingActionButton(
onPressed: _incrementCounter,
tooltip: 'Increment',
child: Icon(Icons.add),
),
);
}
}