Search code examples
androidbroadcastreceiverandroid-developer-api

My android app doesn't run in the backround


So I'm really new to android development and I'm trying to create an app that receives an SMS message and performs some calculations on the message and then saves them in a Shared Preferences file. The app works when it's running and when it's in the background, but once the app is removed from recent apps, the app doesn't work.

Mainactivity

package com.example.myapplication;

import android.content.Intent;
import android.content.SharedPreferences;
import android.os.Bundle;
import android.view.View;
import android.widget.ListView;
import android.widget.TextView;

import androidx.appcompat.app.AppCompatActivity;

public class MainActivity extends AppCompatActivity implements MessageListenerInterface {
    private ListView listView;
    private TextView textView;
    private TextView textView2;
    private TextView textView3;
    private TextView textView4;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);
        textView = findViewById(R.id.textView5);
        textView2 = findViewById(R.id.textView6);
        textView3 = findViewById(R.id.textView10);
        textView4=findViewById(R.id.textView7);
        SharedPreferences ts = getSharedPreferences("spent", MODE_PRIVATE);
        SharedPreferences.Editor tpe = ts.edit();
        textView3.setText(ts.getString("spent","0"));
        MessageBroadcastReceiver.bindListener(this);
        textView4.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View view) {
                SharedPreferences sp = getSharedPreferences("login-auth",MODE_PRIVATE);
                SharedPreferences.Editor spe = sp.edit();
                spe.putBoolean("login-auth",false).apply();
                Intent intent = new Intent(MainActivity.this,login.class);
                startActivity(intent);
            }
        });
    }
    @Override
    public void messageReceived(String message) {
        String S = message.toString();
        //Some silly calculations;
    }
}

Broadcast Receiver

package com.example.myapplication;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.telephony.SmsMessage;
public class MessageBroadcastReceiver extends BroadcastReceiver {
    // creating a variable for a message listener interface on below line.
    private static MessageListenerInterface mListener;
    @Override
    public void onReceive(Context context, Intent intent) {
        // getting bundle data on below line from intent.
        Bundle data = intent.getExtras();
        // creating an object on below line.
        Object[] pdus = (Object[]) data.get("pdus");
        // running for loop to read the sms on below line.
        for (int i = 0; i < pdus.length; i++) {
            // getting sms message on below line.
            SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
            // extracting the sms from sms message and setting it to string on below line.
            String message = smsMessage.getMessageBody();
            // adding the message to listener on below line.
            mListener.messageReceived(message);
        }
    }
    // on below line we are binding the listener.
    public static void bindListener(MessageListenerInterface listener) {
        mListener = listener;
    }
}

android manifest

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    xmlns:tools="http://schemas.android.com/tools" >
    <uses-permission android:name="android.permission.INTERNET"/>
    <uses-feature
        android:name="android.hardware.telephony"
        android:required="false" />

    <uses-permission android:name="android.permission.RECEIVE_SMS" />
    <uses-permission android:name="android.permission.READ_SMS" />


    <application
        android:allowBackup="true"
        android:dataExtractionRules="@xml/data_extraction_rules"
        android:fullBackupContent="@xml/backup_rules"
        android:icon="@mipmap/ic_launcher"
        android:label="@string/app_name"
        android:roundIcon="@mipmap/ic_launcher_round"
        android:supportsRtl="true"
        android:theme="@style/Theme.Material3.Light.NoActionBar"
        tools:targetApi="31" >
        <activity
            android:name=".register"
            android:theme="@style/Theme.Material3.Light.NoActionBar"
            android:parentActivityName=".login"
            android:exported="false" />
        <activity
            android:name=".MainActivity"
            android:theme="@style/Theme.Material3.Light.NoActionBar"
            android:exported="false"/>

        <activity
            android:name=".login"
            android:theme="@style/Theme.Material3.Light.NoActionBar"
            android:exported="true" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
        <receiver
            android:name=".MessageBroadcastReceiver"
            android:exported="true">
            <!-- adding intent filter as sms received -->
            <intent-filter android:priority="999">
                <action android:name="android.provider.Telephony.SMS_RECEIVED" />

            </intent-filter>
        </receiver>
    </application>

</manifest>

I tried to use services and other stuff but I'm clearly doing something wrong. Can someone help me out?


Solution

  • If your app targets API level 26 or higher, you cannot use the manifest to declare a receiver for implicit broadcasts (broadcasts that do not target your app specifically), except for a few implicit broadcasts that are exempted from that restriction. In most cases, you can use scheduled jobs instead.

    From official android docs: Here

    So unless you have a broadcast targeting your specific app, this will not work when the app is closed, although there are some exceptions to this rule.