【问题标题】:Creating Default SMS App in Xamarin.Forms在 Xamarin.Forms 中创建默认 SMS 应用
【发布时间】:2020-08-10 13:36:24
【问题描述】:

我正在 Xamarin 中开发一个应该是默认 SMS 的 SMS 应用程序,我注册了 Sms Receiver 类, 但是当设备收到消息时会出现此错误。

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]]'

我的 Android 清单:

     <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>

我也试过

     <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>

我的接收器,位于: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
        }
     }

我还在 MainActivity.cs 中注册了接收器

   RegisterReceiver(new DroidSmsReceiver(), new IntentFilter("android.provider.Telephony.SMS_DELIVER"));

提前谢谢各位。

【问题讨论】:

    标签: c# android xamarin.forms xamarin.android xamarin-studio


    【解决方案1】:

    您想在 xamarin 表单中实现类似 GIF 的结果吗?

    如果是这样,我使用依赖服务来实现。

    首先,我在 PCL 中创建一个接口

    public interface ISmsReader
        {
            void GetSmsInbox();
        }
    

    您可以在 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();
            }
        }
    

    这是我的MainPage.xaml

     <StackLayout>
            <Button Text="open broadcase" Clicked="Button_Clicked"/>
            <Label x:Name="editorSms"/>
       </StackLayout>
    

    然后,在xxxx.Droid文件夹下实现这个界面。注意:你的new IntentFilter("android.provider.Telephony.SMS_DELIVER")IntentFilter在你的MainActivity.cs是错误的,应该是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);
    
            }
        }
    }
    

    那么,这是我关于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");
            }
        }
    }
    

    如果你已经设置了SmsBroadcastRceiver类上面的属性,你不需要在Android Manifest中清除它。

    这是我的demo(我没有实现runtime权限,如果你测试我的demo,你应该手动添加权限)。

    https://github.com/851265601/BroadcastReceSMS

    ====更新====

    这是我正在运行的 GIF(将消息设置为已读)。

    如果您想将消息设置为已读,首先我们应该将我的应用程序设置为默认的短信应用程序。

    我们必须执行以下步骤(如果我们缺少其中一个,它将不起作用)。

    • 在广播接收器中,包含 SMS_DELIVER_ACTION(“android.provider.Telephony.SMS_DELIVER”)的意图过滤器。广播接收器还必须需要 BROADCAST_SMS 权限。这允许您的应用直接接收传入的 SMS 消息。

    • 在广播接收器中,包含 MIME 类型为“application/vnd.wap.mms-message”的 WAP_PUSH_DELIVER_ACTION (“android.provider.Telephony.WAP_PUSH_DELIVER”) 的意图过滤器。广播接收器还必须需要 BROADCAST_WAP_PUSH 权限。这允许您的应用直接接收传入的彩信。

    • 在传递新消息的 Activity 中,为 ACTION_SENDTO(“android.intent.action.SENDTO”)添加一个带有模式、sms:、smsto:、mms: 和 mmsto: 的意图过滤器。这允许您的应用接收来自其他想要传递消息的应用的意图。

    • 在服务中,为 ACTION_RESPONSE_VIA_MESSAGE ("android.intent.action.RESPOND_VIA_MESSAGE") 包含模式、sms:、smsto:、mms: 和 mmsto: 的意图过滤器。此服务还必须需要 SEND_RESPOND_VIA_MESSAGE 权限。

    如果没有这四个,您的应用将不会列在默认的 SMS 选择对话框中。

    这是我的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>
    

    达到MmsReceiver,HeadlessSmsSendService,ComposeSmsActivity,SmsBroadcastRceiver

    这是关于MmsReceiver.cs的代码。

        public class MmsReceiver : BroadcastReceiver
        {
            public override void OnReceive(Context context, Intent intent)
            {
                Toast.MakeText(context, "Received intent!", ToastLength.Short).Show();
            }
        }
    

    这是关于HeadlessSmsSendService.cs的代码。

        public class HeadlessSmsSendService : Service
        {
            public override IBinder OnBind(Intent intent)
            {
                return null;
            }
        }
    

    这是关于ComposeSmsActivity.cs的代码。

      public class ComposeSmsActivity : Activity
        {
            protected override void OnCreate(Bundle savedInstanceState)
            {
                base.OnCreate(savedInstanceState);
    
                // Create your application here
            }
        }
    

    这是关于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());
                }
            }
        }
    

    我在MainActivity.cs 中添加以下代码以将我的应用程序设置为默认短信应用程序。

                //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);
    

    这是我的新演示。

    https://github.com/851265601/XFormsSMSFilter

    【讨论】:

    • 感谢 Leon,但有没有办法将消息设置为“已读”而不将其设为默认短信应用?
    • 不行,如果你想设置短信为Read,你必须使用ContentResolver来更新短信数据库,你可以参考这个帖子android-developers.googleblog.com/2013/10/…
    • 是的,但问题是我如何在清单中注册 MySmsReader 类,当我这样做时,它只是显示我在问题中发布的错误。
    • 你能帮我解决这个问题吗?
    • @RyanMotal 我已经更新了我的答案,你可以参考一下
    猜你喜欢
    • 2016-11-09
    • 2018-08-19
    • 2013-11-02
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-01-19
    • 1970-01-01
    相关资源
    最近更新 更多