'Flutter Android receiver not working after restart
In flutter app the receivers for BOOT_COMPLETED and SMS_RECEIVED not work when the real device is restarted but work fine in 'android emulator' and the real device before the restart
permission for RECEIVED_SMS
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
permission for BOOT_COMPLETED
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
Class for RECEIVE_SMS is SmsReceiver
Class for BOOT_COMPLETED is BootReceiver
AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
package="ai.torquevision.encredeble"
android:installLocation="internalOnly">
<uses-permission android:name="android.permission.READ_SMS" />
<uses-permission android:name="android.permission.BROADCAST_SMS"
tools:ignore="ProtectedPermissions" />
<uses-permission android:name="android.permission.RECEIVE_SMS"/>
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE"/>
<uses-permission android:name="android.permission.VIBRATE" />
<uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />
<application
android:usesCleartextTraffic="true"
android:label="encredeble"
android:icon="@drawable/logo">
<uses-library android:name="org.apache.http.legacy" android:required="false"/>
<activity
android:name="ai.torquevision.encredeble.MainActivity"
android:supportsPictureInPicture="true"
android:launchMode="singleTop"
android:theme="@style/LaunchTheme"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
<!-- Specifies an Android theme to apply to this Activity as soon as
the Android process has started. This theme is visible to the user
while the Flutter UI initializes. After that, this theme continues
to determine the Window background behind the Flutter UI. -->
<meta-data
android:name="io.flutter.embedding.android.NormalTheme"
android:resource="@style/NormalTheme"
/>
<!-- Displays an Android View that continues showing the launch screen
Drawable until Flutter paints its first frame, then this splash
screen fades out. A splash screen is useful to avoid any visual
gap between the end of Android's launch screen and the painting of
Flutter's first frame. -->
<meta-data
android:name="io.flutter.embedding.android.SplashScreenDrawable"
android:resource="@drawable/launch_background"
/>
<intent-filter>
<action android:name="android.intent.action.MAIN"/>
<category android:name="android.intent.category.LAUNCHER"/>
</intent-filter>
</activity>
<!-- Don't delete the meta-data below.
This is used by the Flutter tool to generate GeneratedPluginRegistrant.java -->
<meta-data
android:name="flutterEmbedding"
android:value="2" />
<receiver android:name=".Utils.BootReceiver" >
<intent-filter >
<action android:name="android.intent.action.BOOT_COMPLETED" />
<action android:name="android.intent.action.LOCKED_BOOT_COMPLETED" />
<action android:name="android.intent.action.QUICKBOOT_POWERON" />
<action android:name="com.htc.intent.action.QUICKBOOT_POWERON"/>
</intent-filter>
</receiver>
<receiver android:name=".Utils.SmsReceiver" android:permission="android.permission.RECEIVE_SMS" android:enabled="true" android:exported="true" >
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
</intent-filter>
</receiver>
</application>
</manifest>
BootReceiver.kt
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.util.Log
import kotlinx.coroutines.delay
import java.lang.Exception
class BootReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("encredeble", "encredeble context: " + context?.toString() + "intent: " + intent?.action);
Log.i("encredeble", "encredeble context: " + context?.toString() + "intent: " + intent?.action);
if(context == null || intent == null){
return;
}
try{
NotificationHandler.notify(context, "Restart action", "action: " + intent?.action);
Log.w("boot_broadcast_poc", "=======================> starting service...")
if(intent.action.equals("android.intent.action.BOOT_COMPLETED") || intent.action.equals("android.intent.action.QUICKBOOT_POWERON") || intent.action.equals("android.intent.action.LOCKED_BOOT_COMPLETED")){
NotificationHandler.notify(context, "Device restarted", "BOOT COMPLETED");
}
}
catch (err: Exception){
NotificationHandler.notify(context, "Restart error", "Error: " + err.message)
}
}
}
SmsReceiver.kt
import ai.torquevision.encredeble.MainActivity
import ai.torquevision.encredeble.R
import android.app.NotificationChannel
import android.app.NotificationManager
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.provider.Telephony
import androidx.core.app.NotificationCompat
import android.telephony.SmsMessage
import android.util.Log
import androidx.core.app.NotificationManagerCompat
import io.flutter.embedding.engine.dart.DartExecutor
import io.flutter.embedding.engine.loader.FlutterLoader
import io.flutter.plugin.common.MethodChannel
import org.json.JSONArray
import org.json.JSONObject
class SmsReceiver: BroadcastReceiver() {
override fun onReceive(context: Context?, intent: Intent?) {
Log.d("Sms receive", "===================================> SMS Received")
if(intent ==null) {
return
}
if(Telephony.Sms.Intents.SMS_RECEIVED_ACTION.equals(intent.action)){
var msg = ""
var msgObj: JSONArray = JSONArray()
for (smsMessage in Telephony.Sms.Intents.getMessagesFromIntent(intent)) {
val messageBody = smsMessage.messageBody
Log.d("msg body", "message body: " + messageBody)
msg = msg + messageBody
var map: JSONObject = JSONObject()
if(msgObj.length() == 0){
map.put("body", messageBody)
map.put("originatingAddress", smsMessage.originatingAddress)
map.put("displayOriginatingAddress", smsMessage.displayOriginatingAddress)
map.put("displayMessageBody", smsMessage.displayMessageBody)
msgObj.put(0, map)
} else {
val expMap = msgObj.get(msgObj.length() - 1) as JSONObject
if(expMap["originatingAddress"] == smsMessage.originatingAddress || expMap["displayOriginatingAddress"] == smsMessage.displayOriginatingAddress){
map = expMap
map.put("body", map["body"].toString() + messageBody)
map.put("displayMessageBody", map["displayMessageBody"].toString() + smsMessage.displayMessageBody)
msgObj.put(msgObj.length() - 1, map)
}else{
map.put("body", messageBody)
map.put("originatingAddress", smsMessage.originatingAddress)
map.put("displayOriginatingAddress", smsMessage.displayOriginatingAddress)
map.put("displayMessageBody", smsMessage.displayMessageBody)
msgObj.put(map)
}
}
}
if(context != null){
SmsMethodChannel.invoke(context, msgObj.toString());
}
}
}
}
Sources
This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.
Source: Stack Overflow
| Solution | Source |
|---|
