I'm developing an SMS app in Xamarin that should be default SMS, I registered the Sms Receiver class, but when the device received a message this error appears.
Java.Lang.RuntimeException: 'Unable to instantiate receivercom.companyName.MySmsApp.DroidSmsReceiver: java.lang.ClassNotFoundException:Didn't find class "com.companyName.MySmsApp.DroidSmsReceiver" on path:DexPathList[[zip file "/data/app/com.companyName.MySmsApp-NaDrepA_GVue_nq4DxzmqA==/base.apk"],nativeLibraryDirectories=[/data/app/com.companyName.MySmsApp-NaDrepA_GVue_nq4DxzmqA==/lib/x86, /data/app/com.companyName.MySmsApp-NaDrepA_GVue_nq4DxzmqA==/base.apk!/lib/x86, /system/lib]]'
my Android Manifest:
<receiver android:name=".DroidSmsReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter android:priority="999" >
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.provider.Telephony.SMS_DELIVER" />
<action android:name="android.provider.Telephony.SMS_DELIVER_ACTION" />
<action android:name="android.intent.action.BOOT_COMPLETED"/>
</intent-filter>
</receiver>
<receiver android:name=".MMSBroadcastReceiver"
android:exported="true"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter android:priority="999" >
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<!-- Activity that allows the user to send new SMS/MMS messages -->
<activity android:name=".ComposeSmsActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</activity>
<service
android:name=".QuickResponseService"
android:enabled="true"
android:exported="true"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE">
<intent-filter>
<category android:name="android.intent.category.DEFAULT" />
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
I also tried
<receiver android:name=".DroidSmsReceiver"
android:permission="android.permission.BROADCAST_SMS">
<intent-filter>
<action android:name="android.provider.Telephony.SMS_RECEIVED" />
<action android:name="android.provider.Telephony.SMS_DELIVER" />
</intent-filter></receiver>
My Receiver, located in : MySmsApp.Droid
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" })]
//[IntentFilter(new[] { "android.provider.Telephony.SMS_DELIVER" })]
public class DroidSmsReceiver : BroadcastReceiver
{
//private const string IntentAction = "android.provider.Telephony.SMS_RECEIVED";
protected string address, message = "";
public override void OnReceive(Context context, Intent intent)
{
//message received
}
}
i also registered the receiver in MainActivity.cs
RegisterReceiver(new DroidSmsReceiver(), new IntentFilter("android.provider.Telephony.SMS_DELIVER"));
Thanks in advance Guys.
Do you want to achieve the resule like following GIF in xamarin forms.?
If so, I used dependency service to achieve that.
Firstly, I create a interface in PCL
public interface ISmsReader
{
void GetSmsInbox();
}
You can use it in the PCL MainPage.xaml.cs
.
public partial class MainPage : ContentPage
{
public MainPage()
{
InitializeComponent();
MessagingCenter.Subscribe<List<string>>(this, "MyMessage", (expense) =>
{
List<string> mylist= expense as List<string>;
string allText= "";
foreach (string item in mylist)
{
allText += item+" ";
}
editorSms.Text = allText;
});
}
private void Button_Clicked(object sender, EventArgs e)
{
Xamarin.Forms.DependencyService.Get<ISmsReader>().GetSmsInbox();
}
}
Here is my MainPage.xaml
.
<StackLayout>
<Button Text="open broadcase" Clicked="Button_Clicked"/>
<Label x:Name="editorSms"/>
</StackLayout>
Then, achieve this interface in the xxxx.Droid folder.Note:Your new IntentFilter("android.provider.Telephony.SMS_DELIVER")
IntentFilter is wrong in your MainActivity.cs
, it should be android.provider.Telephony.SMS_RECEIVED
[assembly: Xamarin.Forms.Dependency(typeof(MySmsReader))]
namespace ScanDemo.Droid
{
public class MySmsReader : ISmsReader
{
public void GetSmsInbox()
{
IntentFilter filter = new IntentFilter();
filter.AddAction("android.provider.Telephony.SMS_RECEIVED");
SmsBroadcastRceiver receiver = new SmsBroadcastRceiver();
Application.Context.RegisterReceiver(receiver, filter);
}
}
}
Then, Here is my code about SmsBroadcastRceiver
.
[BroadcastReceiver(Enabled = true, Exported = true)]
[IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED" })]
public class SmsBroadcastRceiver : BroadcastReceiver
{
public SmsBroadcastRceiver()
{
}
public override void OnReceive(Context context, Intent intent)
{
var msgs = Telephony.Sms.Intents.GetMessagesFromIntent(intent);
List<string> msgList = new List<string>();
foreach (var msg in msgs)
{
msgList.Add(msg.DisplayMessageBody);
}
MessagingCenter.Send<List<string>>(msgList, "MyMessage");
}
}
}
If you have set the attributes above the SmsBroadcastRceiver
class, you do not need to declear it in the Android Manifest.
Here is my demo(I do not achieve the runtime permission, If you test my demo, you should add permission manually).
https://github.com/851265601/BroadcastReceSMS
====Update====
Here is my running GIF(set the message as read).
If you want to set the message as read, Firstly, we should set my application to the default sms app.
We must do following steps(If we lack of one of them, it will not worked).
In a broadcast receiver, include an intent filter for SMS_DELIVER_ACTION ("android.provider.Telephony.SMS_DELIVER"). The broadcast receiver must also require the BROADCAST_SMS permission. This allows your app to directly receive incoming SMS messages.
In a broadcast receiver, include an intent filter for WAP_PUSH_DELIVER_ACTION ("android.provider.Telephony.WAP_PUSH_DELIVER") with the MIME type "application/vnd.wap.mms-message". The broadcast receiver must also require the BROADCAST_WAP_PUSH permission. This allows your app to directly receive incoming MMS messages.
In your activity that delivers new messages, include an intent filter for ACTION_SENDTO ("android.intent.action.SENDTO") with schemas, sms:, smsto:, mms:, and mmsto:. This allows your app to receive intents from other apps that want to deliver a message.
In a service, include an intent filter for ACTION_RESPONSE_VIA_MESSAGE ("android.intent.action.RESPOND_VIA_MESSAGE") with schemas, sms:, smsto:, mms:, and mmsto:. This service must also require the SEND_RESPOND_VIA_MESSAGE permission.
Without all four, your app will not be listed in the default SMS selection dialog.
Here is my AndroidManifest.xml
<manifest xmlns:android="http://schemas.android.com/apk/res/android" android:versionCode="1" android:versionName="1.0" package="com.companyname.scandemo" android:installLocation="auto">
<uses-sdk android:minSdkVersion="21" android:targetSdkVersion="28" />
<application android:label="ScanDemo.Android">
<!-- BroadcastReceiver that listens for incoming MMS messages -->
<receiver android:name=".MmsReceiver"
android:permission="android.permission.BROADCAST_WAP_PUSH">
<intent-filter>
<action android:name="android.provider.Telephony.WAP_PUSH_DELIVER" />
<data android:mimeType="application/vnd.wap.mms-message" />
</intent-filter>
</receiver>
<!-- Activity that allows the user to send new SMS/MMS messages -->
<activity android:name=".ComposeSmsActivity" >
<intent-filter>
<action android:name="android.intent.action.SEND" />
<action android:name="android.intent.action.SENDTO" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</activity>
<!-- Service that delivers messages from the phone "quick response" -->
<service android:name=".HeadlessSmsSendService"
android:permission="android.permission.SEND_RESPOND_VIA_MESSAGE"
android:exported="true" >
<intent-filter>
<action android:name="android.intent.action.RESPOND_VIA_MESSAGE" />
<category android:name="android.intent.category.DEFAULT" />
<data android:scheme="sms" />
<data android:scheme="smsto" />
<data android:scheme="mms" />
<data android:scheme="mmsto" />
</intent-filter>
</service>
</application>
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<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_SMS" />
<uses-permission android:name="android.permission.SEND_SMS" />
<uses-permission android:name="android.permission.RECEIVE_SMS" />
<uses-permission android:name="android.permission.BROADCAST_SMS" />
</manifest>
Achieve the MmsReceiver
, HeadlessSmsSendService
,ComposeSmsActivity
,SmsBroadcastRceiver
Here is code about MmsReceiver.cs
.
public class MmsReceiver : BroadcastReceiver
{
public override void OnReceive(Context context, Intent intent)
{
Toast.MakeText(context, "Received intent!", ToastLength.Short).Show();
}
}
Here is code about HeadlessSmsSendService.cs
.
public class HeadlessSmsSendService : Service
{
public override IBinder OnBind(Intent intent)
{
return null;
}
}
Here is code about ComposeSmsActivity.cs
.
public class ComposeSmsActivity : Activity
{
protected override void OnCreate(Bundle savedInstanceState)
{
base.OnCreate(savedInstanceState);
// Create your application here
}
}
Here is code about SmsBroadcastRceiver.cs
.
[BroadcastReceiver(Enabled = true, Exported = true,Permission = "android.permission.BROADCAST_SMS")]
[IntentFilter(new[] { "android.provider.Telephony.SMS_RECEIVED", "android.provider.Telephony.SMS_DELIVER" })]
public class SmsBroadcastRceiver : BroadcastReceiver
{
public SmsBroadcastRceiver()
{
}
public override void OnReceive(Context context, Intent intent)
{
var msgs = Telephony.Sms.Intents.GetMessagesFromIntent(intent);
List<string> msgList = new List<string>();
string address = "";
string body = "";
foreach (var msg in msgs)
{
msgList.Add(msg.DisplayMessageBody);
address = msg.DisplayOriginatingAddress;
body = msg.DisplayMessageBody;
}
markMessageRead(Android.App.Application.Context, address, body);
MessagingCenter.Send<List<string>>(msgList, "MyMessage");
}
public void markMessageRead(Context context, String number, String body)
{
Android.Net.Uri uri = Android.Net.Uri.Parse("content://sms/inbox");
ICursor cursor = context.ContentResolver.Query(uri, null, null, null, null);
try
{
while (cursor.MoveToNext())
{
if ((cursor.GetString(cursor.GetColumnIndex("address")).Equals(number)) && (cursor.GetInt(cursor.GetColumnIndex("read")) == 0))
{
if (cursor.GetString(cursor.GetColumnIndex("body")).StartsWith(body))
{
String SmsMessageId = cursor.GetString(cursor.GetColumnIndex("_id"));
ContentValues values = new ContentValues();
values.Put("read", true);
context.ContentResolver.Update(Android.Net.Uri.Parse("content://sms/inbox"), values, "_id=" + SmsMessageId, null);
return;
}
}
}
}
catch (Exception e)
{
Log.Error("Mark Read", "Error in Read: " + e.ToString());
}
}
}
I add the following code in MainActivity.cs
to set my application to default sms app.
//Add this to make your app default
Intent intent = new Intent();
intent.SetAction(Telephony.Sms.Intents.ActionChangeDefault);
intent.PutExtra(Telephony.Sms.Intents.ExtraPackageName, this.PackageName);
StartActivity(intent);
Here is my new demo.