August 13, 2021

Google restricting apps with Call log and SMS permission

By lj007

Why Google restricting apps with Call log and SMS permission?

Google introduces new privacy policies. According to that if your will not serve as core app for SMS or Call, your app may blocked by google. 

What is means to developer?

If you develop app which is basically for Call or SMS, you need to set it for default app for that. If your app is for Call, Your user must accept it as default app for Call, otherwise it will not work properly because of new privacy policy. If you only use its function for some time of your app you can probably use its intents, like below:

Phone call Intent

Intent callIntent = new Intent(Intent.ACTION_CALL);  
callIntent.setData(Uri.parse("tel:"+8802177690));//change the number  
startActivity(callIntent);  

SMS Intent

Uri uri = Uri.parse("smsto:YOUR_SMS_NUMBER");   
Intent intent = new Intent(Intent.ACTION_SENDTO, uri);   
intent.putExtra("sms_body", "The SMS text");   
startActivity(intent);  

Share Intent

Intent sendIntent = new Intent();
sendIntent.setAction(Intent.ACTION_SEND);
sendIntent.putExtra(Intent.EXTRA_TEXT, "This is my text to send.");
sendIntent.setType("text/plain");
startActivity(sendIntent);

What it meas to user?

There are so many apps which ask user permissions for only one time access and registered broadcast receivers for all over apps life. It doesn’t means anything good. If you only want to retrieve otp for login why you should register receiver for all life of your app?. It will receive all SMS and based on that you will choose OTP from that. No need to check all call logs if you don’t require it.
Do not worry if you don’t tracking all data from users log. Google has also introduce some intent for that as described above. If you require OTP that google has also made api for that.

SMS Retriever API

To automatically verify mobile number, OTP verification is best option. Due to misuse of SMS READ permission Google has just described this api. 

What it does?

It will create a broadcast receiver(It will not create you have to create), grant SMS read permission for you and once your otp verification is done, it will automatically revoke permission and unregister receiver for you. Is it good way? It is good way. You don’t need that receiver once OTP verification is completed right?. If your receiver stays long, your receiver will called every time when message is coming and it will also perform some action based on that, if you dozens of apps which have registered this receiver all apps wakes up at same time and it will hang your device. So thanks to google to overcome this.

How to implement this? 

It is as simple as you done previously.  Just create SmsRetrieverClient and start it and Send number to server(You need to send it yourself, may be with api call).

// Get an instance of SmsRetrieverClient, used to start listening for a matching
// SMS message.
SmsRetrieverClient client = SmsRetriever.getClient(this /* context */);

// Starts SmsRetriever, which waits for ONE matching SMS message until timeout
// (5 minutes). The matching SMS message will be sent via a Broadcast Intent with
// action SmsRetriever#SMS_RETRIEVED_ACTION.
Task task = client.startSmsRetriever();

// Listen for success/failure of the start Task. If in a background thread, this
// can be made blocking using Tasks.await(task, [timeout]);
task.addOnSuccessListener(new OnSuccessListener() {
  @Override
  public void onSuccess(Void aVoid) {
    // Successfully started retriever, expect broadcast intent
    // ...
  }
});

task.addOnFailureListener(new OnFailureListener() {
  @Override
  public void onFailure(@NonNull Exception e) {
    // Failed to start retriever, inspect Exception for more details
    // ...
  }
});

You need to define global receiver like below

/**
 * BroadcastReceiver to wait for SMS messages. This can be registered either
 * in the AndroidManifest or at runtime.  Should filter Intents on
 * SmsRetriever.SMS_RETRIEVED_ACTION.
 */
public class MySMSBroadcastReceiver extends BroadcastReceiver {

  @Override
  public void onReceive(Context context, Intent intent) {
    if (SmsRetriever.SMS_RETRIEVED_ACTION.equals(intent.getAction())) {
      Bundle extras = intent.getExtras();
      Status status = (Status) extras.get(SmsRetriever.EXTRA_STATUS);

      switch(status.getStatusCode()) {
        case CommonStatusCodes.SUCCESS:
          // Get SMS message contents
          String message = (String) extras.get(SmsRetriever.EXTRA_SMS_MESSAGE);
          // Extract one-time code from the message and complete verification
          // by sending the code back to your server.
          break;
        case CommonStatusCodes.TIMEOUT:
          // Waiting for SMS timed out (5 minutes)
          // Handle the error ...
          break;
      }
    }
  }
}

And define it in Manifest.xml file

<receiver android:exported="true" android:name=".MySMSBroadcastReceiver">
    <intent-filter>
        
    </action></intent-filter>
</receiver>

It is all done. Now you will not break policy and not required any permission in app. If you need to know more about how to save credential or display mobile number or email hint you can visit its official doc here