I have created an Android home screen widget with a button that executes Dart code (specifically, an API call) when clicked. Currently, this functionality only works when the app is in the background. I am looking to make it work even when the app is not in the background. Additionally, I prefer not to use any third-party plugins.
// Java code
public class NewAppWidget extends AppWidgetProvider {
public static String valueToBeDisplayed = "temperature_value";
private static boolean isAlarmStarted = false;
public static int no_of_widget=0;
PendingIntent pendingIntent;
public static FlutterEngine flutterEngine;
public static final String ACTION_AUTO_UPDATE = "AUTO_UPDATE";
public static NewAppWidget appwidgetObj = new NewAppWidget();
public static MethodChannel MethodChannel;
static void updateAppWidget(Context context, AppWidgetManager appWidgetManager, int appWidgetId){
CharSequence widgetText = valueToBeDisplayed;
RemoteViews views = new RemoteViews(context.getPackageName(), R.layout.new_app_widget);
views.setTextViewText(R.id.appwidget_text, widgetText);
Intent buttonIntent = new Intent(context, NewAppWidget.class);
buttonIntent.setAction("com.example.weather_widget2.BUTTON_CLICK");
PendingIntent buttonPendingIntent = PendingIntent.getBroadcast(context, 0,
buttonIntent, PendingIntent.FLAG_IMMUTABLE);
views.setOnClickPendingIntent(R.id.buttonOk, buttonPendingIntent);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, NewAppWidget.class));
for (int w : appWidgetIds) {
appWidgetManager.updateAppWidget(w, views);
}
appWidgetManager.updateAppWidget(appWidgetId, views);
}
@Override
public void onReceive(Context context, Intent intent) {
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, NewAppWidget.class));
if (intent != null && Objects.equals(intent.getAction(), ACTION_AUTO_UPDATE)) {
System.out.println(valueToBeDisplayed + "----");
System.out.println("action auto update has received");
callFlutterMethod(context);
}else{
assert intent != null;
if("com.example.weather_widget2.BUTTON_CLICK".equals(intent.getAction())){
callFlutterMethod(context);
}
}
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
super.onReceive(context, intent);
}
@Override
public void onEnabled(Context context) {
no_of_widget++;
System.out.print("called onEnabled at present no fo widgets are "+no_of_widget);
super.onEnabled(context);
}
@Override
public void onDeleted(Context context, int[] appWidgetIds) {
System.out.println("called on 7777777777777 Deleted at present no fo widgets are "+no_of_widget);
super.onDeleted(context, appWidgetIds);
}
@Override
public void onUpdate(Context context, AppWidgetManager appWidgetManager, int[] appWidgetIds) {
if (!isAlarmStarted) {
isAlarmStarted = true;
scheduleAlarm(context);
}
for (int appWidgetId : appWidgetIds) {
updateAppWidget(context, appWidgetManager, appWidgetId);
}
}
private static void callFlutterMethod(Context context) {
System.out.print("call method flutter method has been called");
if(flutterEngine==null){
System.out.print("again flutter cached++++++++++++++++++++++");
flutterEngine = FlutterEngineCache.getInstance().get("my_engine_id");
}
if(flutterEngine!=null)
{
if(MethodChannel==null) {
MethodChannel = new MethodChannel(flutterEngine.getDartExecutor().getBinaryMessenger(), "my_channel123");
}
MethodChannel.setMethodCallHandler((call, result) -> {
if (call.method.equals("InvokedWidget")){
String arg=call.argument("message");
valueToBeDisplayed=arg;
result.success("sample text has been sent from flutter to android");
System.out.println(valueToBeDisplayed);
AppWidgetManager appWidgetManager = AppWidgetManager.getInstance(context);
int[] appWidgetIds = appWidgetManager.getAppWidgetIds(new ComponentName(context, NewAppWidget.class));
appwidgetObj.onUpdate(context,appWidgetManager,appWidgetIds);
}
});
MethodChannel.invokeMethod("requestLatestData", "");
}
else {
System.out.print("flutter engine has been null");
}
}
private void scheduleAlarm(Context context) {
System.out.println("schedule alarm method is triggered");
Intent intent = new Intent(context, NewAppWidget.class);
intent.setAction(ACTION_AUTO_UPDATE);
pendingIntent = PendingIntent.getBroadcast(context, 0, intent, PendingIntent.FLAG_IMMUTABLE);
AlarmManager alarmManager = (AlarmManager) context.getSystemService(Context.ALARM_SERVICE);
long intervalMillis = 1800000;
alarmManager.setRepeating(AlarmManager.RTC, System.currentTimeMillis(), intervalMillis, pendingIntent);
}
}
public class MainActivity extends FlutterActivity {
@Override
public void configureFlutterEngine(@NonNull FlutterEngine flutterEngine) {
super.configureFlutterEngine(flutterEngine);
FlutterEngineCache.getInstance().put("my_engine_id", flutterEngine);
}
}
// Dart Code
import 'dart:convert';
import 'package:http/http.dart' as http;
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
void main() => runApp(const MyApp());
class MyApp extends StatelessWidget {
const MyApp({super.key});
@override
Widget build(BuildContext context) {
return MaterialApp(
debugShowCheckedModeBanner: false,
title: 'Flutter Demo',
theme: ThemeData(
primarySwatch: Colors.blue,
),
home: const MyHomePage(),
);
}
}
class MyHomePage extends StatefulWidget {
const MyHomePage({super.key});
@override
State<MyHomePage> createState() => _MyHomePageState();
}
class _MyHomePageState extends State<MyHomePage> {
static const channelName = 'my_channel123';
late MethodChannel methodChannel;
void configureChannel() {
methodChannel = const MethodChannel(channelName);
methodChannel.setMethodCallHandler(methodHandler);
}
List<dynamic> lst = [];
Future<void> apiCall() async {
apiData = await http.get(Uri.parse('http://api.open-meteo.com/v1/forecast?latitude=52.52&longitude=13.41&hourly=temperature_2m'));
final body1 = apiData.body;
final json = jsonDecode(body1);
if (apiData.statusCode == 200) {
lst = json['hourly']['temperature_2m'];
}
setState(() {});
}
Future<void> methodHandler(MethodCall call) async {
switch (call.method) {
case "requestLatestData":
display();
break;
default:
print('no method handler for method ${call.method}');
}
}
@override
void initState() {
super.initState();
apiCall();
configureChannel();
}
dynamic apiData;
var channel = const MethodChannel("ChannelName");
dynamic result1;
int num = 0;
late String np;
Future<void> display() async {
np = lst[num].toString();
var dt = DateTime.now();
print("${dt.hour}:${dt.minute}:${dt.second}");
await methodChannel.invokeMethod("InvokedWidget", {'message': np});
setState(() {});
}
void updateData() {
np = lst[num].toString();
num++;
setState(() {});
}
@override
Widget build(BuildContext context) {
return lst.isEmpty
? Container(
color: Colors.blue,
height: MediaQuery.of(context).size.height,
width: MediaQuery.of(context).size.width,
)
: Scaffold(
body: Center(
child: Container(
color: Colors.black,
child: Center(
child: Column(
mainAxisAlignment: MainAxisAlignment.center,
children: [
const Text(
"Current Temperature",
textDirection: TextDirection.rtl,
textAlign: TextAlign.center,
style: TextStyle(color: Colors.white, fontSize: 48, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 30,
),
Text(
lst[num].toString(),
style: const TextStyle(color: Colors.white, fontSize: 32, fontWeight: FontWeight.bold),
),
const SizedBox(
height: 100,
),
ElevatedButton(
onPressed: updateData,
child: const Text(
'Update Temperature',
style: TextStyle(fontWeight: FontWeight.bold, fontSize: 20),
),
)
],
),
),
),
),
);
}
}