【问题标题】:How can I read SMS messages from the device programmatically in Android?如何在 Android 中以编程方式从设备读取 SMS 消息?
【发布时间】:2010-10-25 07:48:41
【问题描述】:

我想从设备中检索 SMS 消息并显示它们?

【问题讨论】:

  • @David Freitas 可信链接 +1
  • @DavidFreitas 这个链接失效了,你能分享一下最新的链接吗?
  • @Khobaib,像往常一样,互联网上的事情转瞬即逝。我在archive.org stackoverflow.com/a/19966227/40961 上找到了一份副本,感谢他们(我最近捐款让他们继续运行)。但是我们应该考虑在这个问题的答案中将页面内容从web.archive.org/web/20121022021217/http://mobdev.olin.edu/… 转换为markdown 语法。大概一个小时的工作。

标签: android sms inbox


【解决方案1】:

使用内容解析器 ("content://sms/inbox") 读取收件箱中的短信。

// public static final String INBOX = "content://sms/inbox";
// public static final String SENT = "content://sms/sent";
// public static final String DRAFT = "content://sms/draft";
Cursor cursor = getContentResolver().query(Uri.parse("content://sms/inbox"), null, null, null, null);

if (cursor.moveToFirst()) { // must check the result to prevent exception
    do {
       String msgData = "";
       for(int idx=0;idx<cursor.getColumnCount();idx++)
       {
           msgData += " " + cursor.getColumnName(idx) + ":" + cursor.getString(idx);
       }
       // use msgData
    } while (cursor.moveToNext());
} else {
   // empty box, no SMS
}

请添加READ_SMS权限。

希望对你有帮助:)

【讨论】:

  • 谢谢!你拼错了“getColumnName”,否则它就像一个魅力。哦,如果有人会使用这个,别忘了添加权限 android.permission.READ_SMS。
  • 这是否也使用了@CommonsWare 在他对已接受答案的评论中指定的未记录的 api?
  • 注意!不要像我一样错过moveToFirst
  • @Krishnabhadra 是的。它使用未记录的“content://sms/inbox”内容提供程序。
  • 问题:使用此功能是否授予开发人员阅读 SMS 收件箱中每条消息的权限?
【解决方案2】:
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
        final String myPackageName = getPackageName();
        if (!Telephony.Sms.getDefaultSmsPackage(this).equals(myPackageName)) {

            Intent intent = new Intent(Telephony.Sms.Intents.ACTION_CHANGE_DEFAULT);
            intent.putExtra(Telephony.Sms.Intents.EXTRA_PACKAGE_NAME, myPackageName);
            startActivityForResult(intent, 1);
        }else {
            List<Sms> lst = getAllSms();
        }
    }else {
        List<Sms> lst = getAllSms();
    }

将应用设置为默认短信应用

    @Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
if (requestCode == 1) {
    if (resultCode == RESULT_OK) {

        if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.KITKAT) {
            final String myPackageName = getPackageName();
            if (Telephony.Sms.getDefaultSmsPackage(mActivity).equals(myPackageName)) {

                List<Sms> lst = getAllSms();
            }
        }
    }
}
}

短信功能

public List<Sms> getAllSms() {
    List<Sms> lstSms = new ArrayList<Sms>();
    Sms objSms = new Sms();
    Uri message = Uri.parse("content://sms/");
    ContentResolver cr = mActivity.getContentResolver();

    Cursor c = cr.query(message, null, null, null, null);
    mActivity.startManagingCursor(c);
    int totalSMS = c.getCount();

    if (c.moveToFirst()) {
        for (int i = 0; i < totalSMS; i++) {

            objSms = new Sms();
            objSms.setId(c.getString(c.getColumnIndexOrThrow("_id")));
            objSms.setAddress(c.getString(c
                    .getColumnIndexOrThrow("address")));
            objSms.setMsg(c.getString(c.getColumnIndexOrThrow("body")));
            objSms.setReadState(c.getString(c.getColumnIndex("read")));
            objSms.setTime(c.getString(c.getColumnIndexOrThrow("date")));
            if (c.getString(c.getColumnIndexOrThrow("type")).contains("1")) {
                objSms.setFolderName("inbox");
            } else {
                objSms.setFolderName("sent");
            }

            lstSms.add(objSms);
            c.moveToNext();
        }
    }
    // else {
    // throw new RuntimeException("You have no SMS");
    // }
    c.close();

    return lstSms;
}

短信类如下:

public class Sms{
private String _id;
private String _address;
private String _msg;
private String _readState; //"0" for have not read sms and "1" for have read sms
private String _time;
private String _folderName;

public String getId(){
return _id;
}
public String getAddress(){
return _address;
}
public String getMsg(){
return _msg;
}
public String getReadState(){
return _readState;
}
public String getTime(){
return _time;
}
public String getFolderName(){
return _folderName;
}


public void setId(String id){
_id = id;
}
public void setAddress(String address){
_address = address;
}
public void setMsg(String msg){
_msg = msg;
}
public void setReadState(String readState){
_readState = readState;
}
public void setTime(String time){
_time = time;
}
public void setFolderName(String folderName){
_folderName = folderName;
}

}

别忘了在你的 AndroidManifest.xml 中定义权限

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

【讨论】:

  • 那是一段不错的代码。只是一件事,时间以毫秒为单位。我认为将其设为人类可读的格式会更好,例如 String receiveDayTime = Functions.dateFromMilisec(Long.valueOf(c.getColumnIndexOrThrow("date")), "hh:mm a MMM dd, yyyy");
  • 用 getter 和 setter 做所有事情的目的是什么,我真的不明白为什么不直接使用 assoc 数组或元素直接访问的类
  • @TomasNavara:查看此代码以了解 getter 和 setter 的使用。 pastebin.com/Nh8YXtyJ
  • @BibaswannBandyopadhyay 如果您不想使用除 android 库和 java 库之外的任何东西。 new SimpleDateFormat("hh:mm", Locale.US).format(new Date(Long.parseLong(_time)));这会给你24小时的时间。
  • mActivity 未定义。这是什么?
【解决方案3】:

这是一个微不足道的过程。你可以在源代码SMSPopup看到一个很好的例子

检查以下方法:

SmsMmsMessage getSmsDetails(Context context, long ignoreThreadId, boolean unreadOnly)
long findMessageId(Context context, long threadId, long _timestamp, int messageType
void setMessageRead(Context context, long messageId, int messageType)
void deleteMessage(Context context, long messageId, long threadId, int messageType)

这是阅读的方法:

SmsMmsMessage getSmsDetails(Context context,
                            long ignoreThreadId, boolean unreadOnly)
{
   String SMS_READ_COLUMN = "read";
   String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;
   String SORT_ORDER = "date DESC";
   int count = 0;
   // Log.v(WHERE_CONDITION);
   if (ignoreThreadId > 0) {
      // Log.v("Ignoring sms threadId = " + ignoreThreadId);
      WHERE_CONDITION += " AND thread_id != " + ignoreThreadId;
   }
   Cursor cursor = context.getContentResolver().query(
                      SMS_INBOX_CONTENT_URI,
                      new String[] { "_id", "thread_id", "address", "person", "date", "body" },
                      WHERE_CONDITION,
                      null,
                      SORT_ORDER);
   if (cursor != null) {
      try {
         count = cursor.getCount();
         if (count > 0) {
            cursor.moveToFirst();
            // String[] columns = cursor.getColumnNames();
            // for (int i=0; i<columns.length; i++) {
            // Log.v("columns " + i + ": " + columns[i] + ": " + cursor.getString(i));
            // }                                         
            long messageId = cursor.getLong(0);
            long threadId = cursor.getLong(1);
            String address = cursor.getString(2);
            long contactId = cursor.getLong(3);
            String contactId_string = String.valueOf(contactId);
            long timestamp = cursor.getLong(4);

            String body = cursor.getString(5);                             
            if (!unreadOnly) {
                count = 0;
            }

            SmsMmsMessage smsMessage = new SmsMmsMessage(context, address,
                          contactId_string, body, timestamp,
                          threadId, count, messageId, SmsMmsMessage.MESSAGE_TYPE_SMS);
            return smsMessage;
         }
      } finally {
         cursor.close();
      }
   }               
   return null;
}

【讨论】:

  • 这不是 Android SDK 的一部分。此代码错误地假设所有设备都支持此未记录和不受支持的内容提供程序。谷歌已经明确表示依赖这个不是一个好主意:android-developers.blogspot.com/2010/05/…
  • @Janusz:没有记录和支持的方法适用于所有设备上的所有 SMS 客户端。
  • @CommonsWare 听到这个消息很难过。那么可能不得不使用这个 API。
  • @Omer 知道如何计算每个联系人的短信数量吗?
  • 代码已移动。搜索 SmsPopupUtils.java 让我在谷歌代码中找到了一个新链接。如果他们再次移动它或完全停止它,这里有一个备份链接 - pastebin.com/iPt7MLyM
【解决方案4】:

从 API 19 开始,您可以为此使用 Telephony 类;由于硬核值不会在每个设备中检索消息,因为内容提供者 Uri 会因设备和制造商而异。

public void getAllSms(Context context) {

    ContentResolver cr = context.getContentResolver();
    Cursor c = cr.query(Telephony.Sms.CONTENT_URI, null, null, null, null);
    int totalSMS = 0;
    if (c != null) {
        totalSMS = c.getCount();
        if (c.moveToFirst()) {
            for (int j = 0; j < totalSMS; j++) {
                String smsDate = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.DATE));
                String number = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.ADDRESS));
                String body = c.getString(c.getColumnIndexOrThrow(Telephony.Sms.BODY));
                Date dateFormat= new Date(Long.valueOf(smsDate));
                String type;
                switch (Integer.parseInt(c.getString(c.getColumnIndexOrThrow(Telephony.Sms.TYPE)))) {
                    case Telephony.Sms.MESSAGE_TYPE_INBOX:
                        type = "inbox";
                        break;
                    case Telephony.Sms.MESSAGE_TYPE_SENT:
                        type = "sent";
                        break;
                    case Telephony.Sms.MESSAGE_TYPE_OUTBOX:
                        type = "outbox";
                        break;
                    default:
                        break;
                }


                c.moveToNext();
            }
        }

        c.close();

    } else {
        Toast.makeText(this, "No message to show!", Toast.LENGTH_SHORT).show();
    }
}

【讨论】:

  • 似乎是唯一不使用未记录 API 且不引用第三方库的答案。
  • 我尝试使用此代码从环聊(这是我的默认短信应用程序)获取短信。相反,它检索了我通过 Messenger 发送的最后一条传出消息……你知道是什么原因造成的吗?
  • @MikiP 使用我的猜测能力我会说 Messenger App 要求您用 Messenger 替换 SMS 管理。它发生在其他一些消息传递应用程序中。我没有其他解释。
  • 别忘了调用 c.close();
  • @SardarAgabejli 如果我们使用像“contenturi:sms”这样的硬核值,它不会对每个设备都相同,但是如果我们使用 Telephony 类,我们可以直接访问那个 conetnt uri 或路径该设备的短信数据库,它是一个指向短信数据库的帮助类
【解决方案5】:

这篇文章有点老了,但这里有另一个简单的解决方案,用于在 Android 中获取与 SMS 内容提供者相关的数据:

使用这个库:https://github.com/EverythingMe/easy-content-providers

  • 获取所有SMS

    TelephonyProvider telephonyProvider = new TelephonyProvider(context);
    List<Sms> smses = telephonyProvider.getSms(Filter.ALL).getList();
    

    每个短信都有所有字段,因此您可以获得所需的任何信息:
    地址、正文、接收日期、类型(收件箱、已发送、草稿、..)、线程ID , ...

  • 凝胶所有MMS:

    List<Mms> mmses = telephonyProvider.getMms(Filter.ALL).getList();
    
  • 凝胶Thread:

    List<Thread> threads = telephonyProvider.getThreads().getList();
    
  • 凝胶所有Conversation

    List<Conversation> conversations = telephonyProvider.getConversations().getList();
    

它适用于ListCursor,并且有一个示例应用程序可以查看它的外观和工作方式。

事实上,它支持所有 Android 内容提供程序,例如:联系人、通话记录、日历…… 包含所有选项的完整文档:https://github.com/EverythingMe/easy-content-providers/wiki/Android-providers

希望它也有帮助:)

【讨论】:

  • github上的源代码和例子都很实用。对于大多数常见的提供者来说,这是一个很好的包装器/外观。谢谢。
【解决方案6】:

已经有多个答案可用,但我认为所有答案都缺少这个问题的重要部分。 在从内部数据库或其表中读取数据之前,我们必须了解数据是如何存储在其中的,然后才能找到上述问题的解决方案:

如何在 Android 中以编程方式从设备读取 SMS 消息?

在android短信表中是这样的

现在您可以从数据库中选择您想要的任何内容。在我们的例子中,我们只需要

id、地址和正文

如果是阅读短信:

1.请求权限

int REQUEST_PHONE_CALL = 1;

   if (ContextCompat.checkSelfPermission(MainActivity.this, Manifest.permission.READ_SMS) != PackageManager.PERMISSION_GRANTED) {
            ActivityCompat.requestPermissions(MainActivity.this, new String[]{Manifest.permission.READ_SMS}, REQUEST_PHONE_CALL);
        }

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

2.现在你的代码是这样的

// Create Inbox box URI
Uri inboxURI = Uri.parse("content://sms/inbox");

// List required columns
String[] reqCols = new String[]{"_id", "address", "body"};

// Get Content Resolver object, which will deal with Content Provider
ContentResolver cr = getContentResolver();

// Fetch Inbox SMS Message from Built-in Content Provider
Cursor c = cr.query(inboxURI, reqCols, null, null, null);

// Attached Cursor with adapter and display in listview
adapter = new SimpleCursorAdapter(this, R.layout.a1_row, c,
        new String[]{"body", "address"}, new int[]{
        R.id.A1_txt_Msg, R.id.A1_txt_Number});
lst.setAdapter(adapter);

我希望这会有所帮助。 谢谢。

【讨论】:

    【解决方案7】:

    第 1 步: 首先我们必须在清单文件中添加权限 喜欢

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

    第二步:然后添加服务短信接收器类来接收短信

    <receiver android:name="com.aquadeals.seller.services.SmsReceiver">
        <intent-filter>
            <action android:name="android.provider.Telephony.SMS_RECEIVED"/>
        </intent-filter>
    </receiver>
    

    第 3 步:添加运行时权限

    private boolean checkAndRequestPermissions()
    {
        int sms = ContextCompat.checkSelfPermission(this, Manifest.permission.READ_SMS);
    
        if (sms != PackageManager.PERMISSION_GRANTED)
        {
            ActivityCompat.requestPermissions(this, new String[]{Manifest.permission.READ_SMS}, REQUEST_ID_MULTIPLE_PERMISSIONS);
            return false;
        }
        return true;
    }
    

    第 4 步:在您的应用中添加这些类并进行测试 接口类

    public interface SmsListener {
       public void messageReceived(String messageText);
    }
    

    SmsReceiver.java

    public class SmsReceiver extends BroadcastReceiver {
        private static SmsListener mListener;
        public Pattern p = Pattern.compile("(|^)\\d{6}");
        @Override
        public void onReceive(Context context, Intent intent) {
            Bundle data  = intent.getExtras();
            Object[] pdus = (Object[]) data.get("pdus");
            for(int i=0;i<pdus.length;i++)
            {
                SmsMessage smsMessage = SmsMessage.createFromPdu((byte[]) pdus[i]);
                String sender = smsMessage.getDisplayOriginatingAddress();
                String phoneNumber = smsMessage.getDisplayOriginatingAddress();
                String senderNum = phoneNumber ;
                String messageBody = smsMessage.getMessageBody();
                try{
                    if(messageBody!=null){
                        Matcher m = p.matcher(messageBody);
                        if(m.find()) {
                            mListener.messageReceived(m.group(0));
                        }
                    }
                }
                catch(Exception e){}
            }
        }
        public static void bindListener(SmsListener listener) {
            mListener = listener; 
        }
    }
    

    【讨论】:

    • 模式有什么作用?
    • 嗯... ("com.aquadeals.seller.services.SmsReceiver") 是通用服务名称吗?
    • 这不是服务名称,即我的应用程序中的 SmsReceiver 类路径
    • 为什么需要 LOCATION 的权限?
    • 我正在尝试制作一个应用程序,即使应用程序已被杀死,它也会向用户弹出短信内容
    【解决方案8】:

    Google Play 服务有两个 API,可用于简化基于 SMS 的验证过程

    SMS Retriever API

    提供完全自动化的用户体验,无需用户手动输入验证码,也无需任何额外的应用权限,应尽可能使用。但是,它确实需要您在消息正文中放置自定义哈希码,因此您还必须控制服务器端

    • 消息要求 - 唯一标识您的应用的 11 位哈希码
    • 发件人要求 - 无
    • 用户互动 - 无

    Request SMS Verification in an Android App

    Perform SMS Verification on a Server

    SMS User Consent API

    不需要自定义哈希码,但需要用户批准您的应用访问包含验证码的消息的请求。为了尽量减少向用户显示错误消息的机会,SMS User Consent 将过滤掉来自用户联系人列表中发件人的消息。

    • 消息要求 - 至少包含一个数字的 4-10 位字母数字代码
    • 发件人要求 - 发件人不能在用户的联系人列表中
    • 用户互动 - 一键批准

    The SMS User Consent API 是 Google Play 服务的一部分。要使用它,您至少需要以下库中的 17.0.0 版本:

    implementation "com.google.android.gms:play-services-auth:17.0.0"
    implementation "com.google.android.gms:play-services-auth-api-phone:17.1.0"
    

    第 1 步:开始收听 SMS 消息

    SMS User Consent 将侦听包含一次性代码的传入 SMS 消息长达五分钟。它不会查看在启动之前发送的任何消息。如果您知道将发送一次性代码的电话号码,您可以指定senderPhoneNumber,或者如果您不知道,null 将匹配任何号码。

     smsRetriever.startSmsUserConsent(senderPhoneNumber /* or null */)
    

    第 2 步:请求同意阅读消息

    一旦您的应用收到包含一次性代码的消息,它就会收到广播通知。此时,您没有同意阅读该消息 - 相反,您会收到一个Intent,您可以开始提示用户同意。在您的BroadcastReceiver 中,您使用extras 中的Intent 显示提示。 当您启动该意图时,它会提示用户授予阅读单条消息的权限。他们将看到他们将与您的应用共享的全部文本。

    val consentIntent = extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
    startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
    

    第 3 步:解析一次性代码并完成短信验证

    当用户点击“Allow” 时——是时候真正阅读消息了!在onActivityResult里面可以从数据中获取短信全文:

    val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
    

    然后您解析 SMS 消息并将一次性代码传递到您的后端!

    【讨论】:

    • 4-10 digit alphanumeric code containing at least one number 你能解释一下这是什么意思吗?这是否意味着整个消息的长度应该是短信代码的 4-10 个字符?
    • 也谢谢你
    • 这仅适用于 OTP 验证,对吗?如何阅读手机内的所有其他消息,所有短信等?有没有新的API,请告诉我。快乐编码! :)
    • 我们总是遇到超时错误。请帮帮我
    【解决方案9】:

    最简单的功能

    为了阅读短信,我编写了一个返回对话对象的函数:

    class Conversation(val number: String, val message: List<Message>)
    class Message(val number: String, val body: String, val date: Date)
    
    fun getSmsConversation(context: Context, number: String? = null, completion: (conversations: List<Conversation>?) -> Unit) {
            val cursor = context.contentResolver.query(Telephony.Sms.CONTENT_URI, null, null, null, null)
    
            val numbers = ArrayList<String>()
            val messages = ArrayList<Message>()
            var results = ArrayList<Conversation>()
    
            while (cursor != null && cursor.moveToNext()) {
                val smsDate = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.DATE))
                val number = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.ADDRESS))
                val body = cursor.getString(cursor.getColumnIndexOrThrow(Telephony.Sms.BODY))
    
                numbers.add(number)
                messages.add(Message(number, body, Date(smsDate.toLong())))
            }
    
            cursor?.close()
    
            numbers.forEach { number ->
                if (results.find { it.number == number } == null) {
                    val msg = messages.filter { it.number == number }
                    results.add(Conversation(number = number, message = msg))
                }
            }
    
            if (number != null) {
                results = results.filter { it.number == number } as ArrayList<Conversation>
            }
    
            completion(results)
        }
    

    使用:

    getSmsConversation(this){ conversations ->
        conversations.forEach { conversation ->
            println("Number: ${conversation.number}")
            println("Message One: ${conversation.message[0].body}")
            println("Message Two: ${conversation.message[1].body}")
        }
    }
    

    或者只获取特定号码的对话:

    getSmsConversation(this, "+33666494128"){ conversations ->
        conversations.forEach { conversation ->
            println("Number: ${conversation.number}")
            println("Message One: ${conversation.message[0].body}")
            println("Message Two: ${conversation.message[1].body}")
        }
    }
    

    【讨论】:

      【解决方案10】:

      Kotlin 代码读取短信:

      1- 将此权限添加到 AndroidManifest.xml :

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

      2-创建一个广播接收器类:

      package utils.broadcastreceivers
      
      import android.content.BroadcastReceiver
      import android.content.Context
      import android.content.Intent
      import android.telephony.SmsMessage
      import android.util.Log
      
      class MySMSBroadCastReceiver : BroadcastReceiver() {
      override fun onReceive(context: Context?, intent: Intent?) {
          var body = ""
          val bundle = intent?.extras
          val pdusArr = bundle!!.get("pdus") as Array<Any>
          var messages: Array<SmsMessage?>  = arrayOfNulls(pdusArr.size)
      
       // if SMSis Long and contain more than 1 Message we'll read all of them
          for (i in pdusArr.indices) {
              messages[i] = SmsMessage.createFromPdu(pdusArr[i] as ByteArray)
          }
            var MobileNumber: String? = messages[0]?.originatingAddress
             Log.i(TAG, "MobileNumber =$MobileNumber")         
             val bodyText = StringBuilder()
              for (i in messages.indices) {
                  bodyText.append(messages[i]?.messageBody)
              }
              body = bodyText.toString()
              if (body.isNotEmpty()){
             // Do something, save SMS in DB or variable , static object or .... 
                             Log.i("Inside Receiver :" , "body =$body")
              }
          }
       }
      

      3-如果是 Android 6 及更高版本,则获取 SMS 权限:

         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.M && 
          ActivityCompat.checkSelfPermission(context!!,
                  Manifest.permission.RECEIVE_SMS
              ) != PackageManager.PERMISSION_GRANTED
          ) { // Needs permission
      
                  requestPermissions(arrayOf(Manifest.permission.RECEIVE_SMS),
                  PERMISSIONS_REQUEST_READ_SMS
              )
      
          } else { // Permission has already been granted
      
          }
      

      4- 将此请求代码添加到 Activity 或片段:

       companion object {
          const val PERMISSIONS_REQUEST_READ_SMS = 100
         }
      

      5- 覆盖检查权限请求结果乐趣:

       override fun onRequestPermissionsResult(
          requestCode: Int, permissions: Array<out String>,
          grantResults: IntArray
      ) {
          when (requestCode) {
      
              PERMISSIONS_REQUEST_READ_SMS -> {
                  if (grantResults[0] == PackageManager.PERMISSION_GRANTED) {
                      Log.i("BroadCastReceiver", "PERMISSIONS_REQUEST_READ_SMS Granted")
                  } else {
                      //  toast("Permission must be granted  ")
                  }
              }
          }
      }
      

      【讨论】:

        【解决方案11】:
        String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0" : null;
        

        更改者:

        String WHERE_CONDITION = unreadOnly ? SMS_READ_COLUMN + " = 0 " : SMS_READ_COLUMN + " = 1 ";
        

        【讨论】:

          【解决方案12】:

          Hier 是一个很棒的视频教程!!!!效果很好!!!

          它是来自带有数字的 Google 表格列表和 Android 应用程序的组合。 (对于没有编码人员也很容易遵循教程!!!

          点击教程链接:

          https://www.youtube.com/watch?v=PReU4ITp37I&list=PLuB9drjjGa0QvFzWq_bwO8bOTRaWpdP_d&index=2

          这是 Google 应用脚本的代码:

          const SHEET_URL = "https://docs.google.com/spreadsheets/d/16_fp7lQsnaMLaDYMVsE5YxsohQBANllEVcZeMP5ZpiU/edit#gid=0";
          const SHEET_NAME = "SMS";
          
          const doGet = () => {
            const sheet = SpreadsheetApp.openByUrl(SHEET_URL).getSheetByName(SHEET_NAME);
            const [header, ...data] = sheet.getDataRange().getDisplayValues();
            
          
            const PHONE = header.indexOf("Phone");
            const TEXT = header.indexOf("Text");
            const STATUS = header.indexOf("Status");
          
            const output = [];
          
           data.forEach((row, index) => {
            if (row[STATUS] === "") {
              output.push([index+1, row[PHONE], row[TEXT]]);
            }
          });
          
          const json = JSON.stringify(output);
          
          return ContentService.createTextOutput(json).setMimeType(ContentService.MimeType.TEXT);
          }
          
          const doPost = (e) => {
            const sheet = SpreadsheetApp.openByUrl(SHEET_URL).getSheetByName(SHEET_NAME);
            const [header] = sheet.getRange("A1:1").getValues();
            const STATUS = header.indexOf("Status");
            var rowId = Number(e.parameter.row);
            sheet.getRange(rowId + 1, STATUS +1).setValue("SMS Sent");
            return ContentService.createTextOutput("").setMimeType(ContentService.MimeType.TEXT);
          }
          

          然后您只需关注视频的第二部分,他在 MIT App Inventer 中构建 Android APP。我做了一个截图来看看这个项目

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2011-11-16
            • 1970-01-01
            • 2019-07-26
            相关资源
            最近更新 更多