2

In one application (App1) I am broadcasting a message. This code below is correct -> the broadcast is detected if I try to get Broadcast in the same project.

sendBroadcast(new Intent("com.example.MESSAGE_INTENT").putExtra("MESSAGE", ((EditText) findViewById(R.id.textField)).getText()));

I created App2 which has a BroadcastReceiver which waits for the broadcasted Intent but the method onReceive is never invoked.

How to change the BroadcastReceiver app to make the service work in background all the time?


App2 manifest and code:

package com.example;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.util.Log;
import android.widget.Toast;

public class MyReceiver extends BroadcastReceiver {
    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("WORKS" , "!!!!!!!!!!");
        Toast.makeText(context, "CAUGHTt\n" + intent.getExtras().getString("MESSAGE"), Toast.LENGTH_LONG).show();
    }
}

           <manifest xmlns:android="http://schemas.android.com/apk/res/android"
        package="com.jjoe64" >

        <permission-group
            android:name="com.examples.my_permissions"
            android:label="my permissions groupd" />

        <permission
            android:name="com.examples.my_permissions.MY_PERMISSION"
            android:label="my permission"
            android:permissionGroup="com.examples.my_permissions" />

        <application>
            <receiver
                android:name="MyReceiver"
                android:exported="true"
                android:permission="com.examples.my_permissions.MY_PERMISSION" >
                <intent-filter>
                    <action android:name="com.example.MESSAGE_INTENT" />
                </intent-filter>
            </receiver>


            <service android:name="BackgroundService" />
        </application>

    </manifest>

Broadcaster MANIFEST

<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example"
    android:exported="true" >

    <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" />

    <permission-group
        android:name="com.examples.my_permissions"
        android:label="my permissions groupd" />

    <permission
        android:name="com.examples.my_permissions.MY_PERMISSION"
        android:label="my permission"
        android:permissionGroup="com.examples.my_permissions" />

    <application>
        <receiver
            android:name="com.example.MyReceiver"
            android:exported="true"
            android:permission="com.examples.my_permissions.MY_PERMISSION" >
            <intent-filter>
                <action android:name="com.example.MESSAGE_INTENT" />
                <action android:name="android.intent.action.AIRPLANE_MODE" />
            </intent-filter>
        </receiver>
    </application>

</manifest>

MAJOR EDIT

I have created an another application with MainActivity there I have created final BroadcastReceiver:

CODE:

package com.example.receiver2;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.os.Bundle;
import android.support.v4.app.Fragment;
import android.support.v7.app.ActionBarActivity;
import android.util.Log;
import android.view.LayoutInflater;
import android.view.Menu;
import android.view.MenuItem;
import android.view.View;
import android.view.ViewGroup;
import android.widget.Toast;

public class MainActivity extends ActionBarActivity {
final BroadcastReceiver br = new BroadcastReceiver() {

    @Override
    public void onReceive(Context context, Intent intent) {
        Log.i("WORKS" , "!!!!!!!!!!");
        Toast.makeText(context, "CAUGHTt\n" + intent.getExtras().getString("MESSAGE"), Toast.LENGTH_LONG).show();
    }
};
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        if (savedInstanceState == null) {
            getSupportFragmentManager().beginTransaction().add(R.id.container, new PlaceholderFragment()).commit();
        }
    }

    @Override
    public boolean onCreateOptionsMenu(Menu menu) {

        // Inflate the menu; this adds items to the action bar if it is present.
        getMenuInflater().inflate(R.menu.main, menu);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        // Handle action bar item clicks here. The action bar will
        // automatically handle clicks on the Home/Up button, so long
        // as you specify a parent activity in AndroidManifest.xml.
        int id = item.getItemId();
        if (id == R.id.action_settings) {
            return true;
        }
        return super.onOptionsItemSelected(item);
    }

    /**
     * A placeholder fragment containing a simple view.
     */
    public static class PlaceholderFragment extends Fragment {

        public PlaceholderFragment() {
        }

        @Override
        public View onCreateView(LayoutInflater inflater, ViewGroup container, Bundle savedInstanceState) {
            View rootView = inflater.inflate(R.layout.fragment_main, container, false);
            return rootView;
        }
    }

}

Manifest:

<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
    package="com.example.receiver2"
    android:versionCode="1"
    android:versionName="1.0" >

    <uses-sdk
        android:minSdkVersion="8"
        android:targetSdkVersion="19" />

    <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" />
    <uses-permission android:name="android.permission.RECEIVE_BOOT_COMPLETED" />

    <permission-group
        android:name="com.examples.my_permissions"
        android:label="my permissions groupd" />

    <permission
        android:name="com.examples.my_permissions.MY_PERMISSION"
        android:label="my permission"
        android:permissionGroup="com.examples.my_permissions" />

    <application
        android:allowBackup="true"
        android:icon="@drawable/ic_launcher"
        android:label="@string/app_name"
        android:theme="@style/AppTheme" >
        <receiver
            android:name="com.example.MyReceiver"
            android:exported="true" >
            <intent-filter>
                <action android:name="com.example.MESSAGE_INTENT" />
                <action android:name="android.intent.action.BOOT_COMPLETED" />
            </intent-filter>
        </receiver>

        <activity
            android:name="com.example.receiver2.MainActivity"
            android:label="@string/app_name" >
            <intent-filter>
                <action android:name="android.intent.action.MAIN" />

                <category android:name="android.intent.category.LAUNCHER" />
            </intent-filter>
        </activity>
    </application>

</manifest>

BUT I GET AN EXCEPTION:

04-18 10:16:46.332: E/AndroidRuntime(1244): FATAL EXCEPTION: main
04-18 10:16:46.332: E/AndroidRuntime(1244): Process: com.example.receiver2, PID: 1244
04-18 10:16:46.332: E/AndroidRuntime(1244): java.lang.RuntimeException: Unable to instantiate receiver com.example.MyReceiver: java.lang.ClassNotFoundException: Didn't find class "com.example.MyReceiver" on path: DexPathList[[zip file "/data/app/com.example.receiver2-1.apk"],nativeLibraryDirectories=[/data/app-lib/com.example.receiver2-1, /system/lib]]
04-18 10:16:46.332: E/AndroidRuntime(1244):     at android.app.ActivityThread.handleReceiver(ActivityThread.java:2400)
Yoda
  • 17,363
  • 67
  • 204
  • 344
  • 1
    I think you might need to add `uses-permission` to your manifest - check my update – Richard Le Mesurier Apr 18 '14 at 13:39
  • @RichardLeMesurier Thank you, I'll check it as fast as I can, my emulator has crashed. – Yoda Apr 18 '14 at 13:45
  • @RichardLeMesurier I added uses permission(please have a look at the edit). Now I try just to detect ANY broadcasted information by the system I tried to check when the phone goes into airplane mode but it just not working. Please look at the edit. – Yoda Apr 18 '14 at 13:56
  • @RichardLeMesurier maybe it has someting to do with name of the classes. Before I had sth like that in the manifest: ` ` – Yoda Apr 18 '14 at 13:57
  • @RichardLeMesurier Please take a look at MAJOR EDIT. Meanwhile I try that stuff from your link. – Yoda Apr 18 '14 at 14:20
  • I added some simple demo code that should get you up and running. Once you have imported my code, you will be able to find the issue in your app quite quickly, I am sure of it. Hope that helps. – Richard Le Mesurier Apr 20 '14 at 13:01

1 Answers1

4

v6 - Sample code on github

In case it helps, I put together a very quick demo app (for Eclipse) which contains a single exported, insecure BroadcastReceiver which you can use as a template. I have stored it on my github account:

You can use it to follow my advice given in v3 of my answer, step 2, where I suggested you get a simple exported BroadcastReceiver working.

I am sure the rest of the process will be quite simple once you have this up and running.


v5 - Manifest receiver as separate class

You can declare a BroadcastReceiver in two different ways:

  • as a field in another class (as in your MainActivity)
  • or as a separate class

When declared in another class, you need to use the methods ContextWrapper.registerReceiver() and ContextWrapper.unregisterReceiver() to register for intents. Your code needs to do this, so your app must be running in order to receive the broadcast.

If you want to "wake up" your app with a broadcast, that is when you declare the receiver in the manifest (like you did). In that case, your BroadcastReceiver will be a separate class file:

package mobiric.demo;

import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;

/**
 * Must be declared in the manifest.
 */
public class MobiricReceiver extends BroadcastReceiver
{
    @Override
    public void onReceive(Context context, Intent intent)
    {
        // do something
    }
}

It looks like you are mixing up these 2 techniques. I think you need the 2nd technique:

  • declare in manifest
  • create separate class file based on code

v4 - Manually launch both apps

The last thing I can think of at the moment is that I think you need to manually launch your app before the system allows a BroadcastReceiver to work.

So be sure to launch any Activity in your app before testing.

Here's a blog post about that:


v3 - Grant your app the Custom Permission

Oh wait - you haven't declared <uses-permission android:name="com.examples.my_permissions.MY_PERMISSION" /> in your manifest.

But I would normally expect logcat to tell you that you have a permission issue.

For what it's worth, I would break this issue down into a couple of steps:

  1. remove all required custom permissions from both apps
  2. debug your broadcast receiver so that it works in this insecure configuration
  3. finally add the custom permissions

That way you isolate potential problems so you are only ever dealing with one tricky issue at a time. It will make it easier to focus on the problem without having other possibilities to track down.

In addition, by removing the custom permissions at development time, it enables you to use ADB to test your receiver, which can save a lot of time. Look for details on the adb shell am broadcast ... here:


v2 - Sign your apps to use Custom Permissions

Original question updated with exported="true".

Using custom permissions requires both apps to be signed, using the same signing key.

However I have run into unsolved "custom permission" issues in the past. Basically my new custom permissions were not being granted on the device. Uninstalling and reinstalling the app did NOT make any difference - it seemed that the system stored that custom permission in a place that I could not update it.

Here is the related post on this forum - unfortunately I was never able to solve the issue, and had to live with the provided workaround:


v1 - Export the BroadcastReceiver

You need to "export" your BroadcastReceiver by putting exported="true" in the manifest declaration of the receiver.

See change below:

    <receiver
        android:name="MyReceiver"
        android:permission="com.examples.my_permissions.MY_PERMISSION"
        android:exported="true" >

        <intent-filter>
            <action android:name="com.example.MESSAGE_INTENT" />
        </intent-filter>
    </receiver>

Note: future readers of this answer, please note that the original post included a permission. This prevent security issues, and requires that the calling app is signed with the same signature.

Community
  • 1
  • 1
Richard Le Mesurier
  • 29,432
  • 22
  • 140
  • 255
  • Thank you I have updated the original post -> I added to the manifest `android:exported="true" but there is still no ouptput on the Logcat. – Yoda Apr 18 '14 at 13:19
  • I do not think so I posted the `Broadcaster` manifest in OP. There is another receiver because first I tested receivers inside that application. How to sign the `Broadcaster` to export? – Yoda Apr 18 '14 at 13:22
  • 1
    I needed create an empty Activity. If this is the only solution it shows how Android scatterbrained in compare to Windows Phone. Thank you for your help, you write your answers really neatly. – Yoda Apr 18 '14 at 19:43
  • @yoda thx for that. but it sounds strange. If you want more input on this feel free to post final code, or a new question and link me to it. I use this type of thing quite often and it makes good sense to me fwiw. Either way, I hope you sorted your issue out, that's what really counts. – Richard Le Mesurier Apr 18 '14 at 21:09