When I trying to retrieve phone number with Credentials api some device failed to showing phone number picker dialog and just showing empty dialog and the dialog disappear quickly with sliding animation.
Below is my code sample.
val hintRequest = HintRequest.Builder().setPhoneNumberIdentifierSupported(true).build()
val options = CredentialsOptions.Builder().forceEnableSaveDialog().build()
val credentialsClient = Credentials.getClient(applicationContext, options)
val intent = credentialsClient.getHintPickerIntent(hintRequest)
try {
startIntentSenderForResult(
intent.intentSender,
CREDENTIAL_PICKER_REQUEST, null, 0, 0, 0, Bundle()
)
} catch (e: IntentSender.SendIntentException) {
e.printStackTrace()
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
CREDENTIAL_PICKER_REQUEST ->
if (resultCode == Activity.RESULT_OK && data != null) {
val credential = data.getParcelableExtra<Credential>(Credential.EXTRA_KEY)
val phoneNumber = credential?.id
}
}
}
Dependencies:
implementation 'com.google.android.gms:play-services-auth:20.1.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:18.0.1'
implementation 'androidx.work:work-runtime-ktx:2.7.1'
It's working fine in below Android 12 but not able to work in Android 12
Is There any solution for the same?
This is a know bug to google, when the SIM does not provide the phone number:
You can star this issue:
https://issuetracker.google.com/issues/77884951
The initial filing however was on Apr 11, 2018 and there is no update yet. So I would consider living either with the UI glitch or disable that functionality.
There has been an update on the auth library:
https://developers.google.com/android/guides/releases#february_01_2022
But I was not able to find any changelog.
Lets just hope, Google will fix this issue in future.
EDIT:
After re-reading your question, this issue does not answer your question. Might be a permission problem, have you tried downgrading your auth version for a retest?
Related
From Jan 9th, 2019 Google will remove apps from Playstore with permissions READ SMS AND CALL LOG, if they don’t explain the necessity.
Google introduced SMS Retriever API to automatically fetch a verification code sent via SMS within the app.
But those APIs are not clearly expressed and is very confusing. I don't know if it's me who thinks it is confusing. Anyhow, here is what I have looked into to read SMS but I could understand nothing.
I am not sure if this is the correct link to read SMS automatically.
https://developers.google.com/identity/sms-retriever/request
I used these dependencies
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.0.0'
There is one good tutorial to implement auto-read SMS but some of the APIs are deprecated so I'm trying to find any simple explanation to implement auto-read SMS in Android.
Here is the link to that tutorial
https://androidwave.com/automatic-sms-verification-android/
You should use sms retriever api for reading otp messages. Here is how you can do that.
You need below 2 dependencies for sms retrieval code
implementation 'com.google.android.gms:play-services-auth:17.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.1.0'
Define few variables like this in your activity/fragment
private val SMS_CONSENT_REQUEST = 2
private lateinit var smsVerificationReceiver: BroadcastReceiver
In your onCreate() method start SMS retriever
SmsRetriever.getClient(this).startSmsUserConsent(null)
smsReceiver()
val intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
registerReceiver(smsVerificationReceiver, intentFilter)
Below is the method for broadcast receiver
private fun smsReceiver() {
smsVerificationReceiver = object : BroadcastReceiver() {
override fun onReceive(context: Context, intent: Intent) {
if (SmsRetriever.SMS_RETRIEVED_ACTION == intent.action) {
val extras = intent.extras
val smsRetrieverStatus = extras?.get(SmsRetriever.EXTRA_STATUS) as Status
when (smsRetrieverStatus.statusCode) {
CommonStatusCodes.SUCCESS -> {
// Get consent intent
val consentIntent =
extras.getParcelable<Intent>(SmsRetriever.EXTRA_CONSENT_INTENT)
try {
// Start activity to show consent dialog to user, activity must be started in
// 5 minutes, otherwise you'll receive another TIMEOUT intent
startActivityForResult(consentIntent, SMS_CONSENT_REQUEST)
} catch (e: ActivityNotFoundException) {
// Handle the exception ...
}
}
CommonStatusCodes.TIMEOUT -> {
// Time out occurred, handle the error.
}
}
}
}
}
}
And then in onActivityResult() you can get the verification code
public override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
// ...
SMS_CONSENT_REQUEST ->
// Obtain the phone number from the result
if (resultCode == Activity.RESULT_OK && data != null) {
// Get SMS message content
val message = data.getStringExtra(SmsRetriever.EXTRA_SMS_MESSAGE)
// Extract one-time code from the message and complete verification
// `message` contains the entire text of the SMS message, so you will need
// to parse the string.
val oneTimeCode = parseOneTimeCode(message) // define this function
et_otp.setText(oneTimeCode.toString())
// send one time code to the server
} else {
// Consent denied. User can type OTC manually.
}
}
}
Also don't forget to unregister receiver in onDestroy() method
unregisterReceiver(smsVerificationReceiver)
I am new to kotlin and android programming, and it seems like this language is moving rather quick without some backwads capabilities.
Here are my two main functions in MainActivity.kt
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
cameraButton.setOnClickListener {
val callCameraIntent = Intent(MediaStore.ACTION_IMAGE_CAPTURE)
if(callCameraIntent.resolveActivity(packageManager) != null) {
startActivityForResult(callCameraIntent, CAMERA_REQUEST_CODE)
}
}
replaceFragment(ReportsFragment())
bottom_navigation.setOnNavigationItemSelectedListener(mOnNavigationItemSelectedListener)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val dt: Intent? = data
when(requestCode) {
CAMERA_REQUEST_CODE -> {
if(resultCode == Activity.RESULT_OK && data != null) {
//if(data != null) {
//&& data != null){
photoImageView.setImageBitmap(data.extras.get("data") as Bitmap)
}
}
else -> {
Toast.makeText(this, "Unrecognized request code", Toast.LENGTH_SHORT).show()
}
}
}
The error seems to come in the "WHEN" block of onActivityResult.
I have wrapped the data (Intent being passed) in null checks, tried to declare it as a new value with a null check, but it constantly gets the same warning when compiling:
Unsafe use of a nullable receiver of type Bundle?
It also keeps saying this depreciated warning:
Deprecated Gradle features were used in this build, making it incompatible with Gradle 6.0.
I have switched the gradle version to 5.1.1 and have the android Gradle plugin currently at 3.4.0 (could either of these be part of my issue)
The data.extras might be null, therefore make sure to use it with ?. and as?:
photoImageView.setImageBitmap(data?.extras?.get("data") as? Bitmap)
All three make sure that if data, data.extras or "data" are null or not a Bitmap, the chain itself is null.
The deprecated Gradle features are usually warnings about deprecated APIs. Just make sure to update all your plugins to the newest ones and don't update to Gradle 6 as long as you require plugins which don't adapt to the new API. But for now it's only warning you about relevant changes.
I am trying to implement `KeyManager' into my app. When authorized action is needed, user is prompted with pattern for unlock. I observe result of this in my activity and based on result I proceed to further action. Following is code I am using,
private const val RESULT_OK = 99
val km = getSystemService(Context.KEYGUARD_SERVICE) as KeyguardManager
val i = km.createConfirmDeviceCredentialIntent("Name", "Something")
i?.let { ind ->
startActivityForResult(ind, RESULT_OK)
// startActivityForResult(Intent(this#LoginActivity, AnotherActivity::class.java), RESULT_OK) //This works
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
Log.i("TAG======", requestCode.toString() + "--" + resultCode.toString())
}
Whenever I am using startActivityForResult(ind, RESULT_OK) onActivityResult is not called but when I used any other activity like startActivityForResult(Intent(this#LoginActivity, AnotherActivity::class.java), RESULT_OK) , onActivityResult is getting called after activity is finished. Am I missing something? I am testing this on physical device (OnePlus 5t) running Android 8.1.
I found the answer after 2 hours of debugging ! This was happening because I was using RESULT_OK constant as private. As soon as I made it public, my KeyManager was working properly! I assume system was taking it as a 0 and hence it was not returning anything to activity :)
I'm trying to connect my game to Google Play Games Services, but when I try to login, it always returns me an error code 8 (internal error).
The code is copy pasted from Google example:
lateinit var signInClient: GoogleSignInClient
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.layout_settings)
settings_login.setOnClickListener { login() }
signInClient = GoogleSignIn.getClient(this,
GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_GAMES_SIGN_IN).build()
)
}
private fun login() {
startActivityForResult(signInClient.signInIntent, 9001)
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
if (requestCode != 9001) {
return
}
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
try {
val account = task.getResult(ApiException::class.java)
onConnected(account)
} catch (apiException: ApiException) {
var message: String? = apiException.message
if (message == null || message.isEmpty()) {
message = getString(R.string.signin_other_error)
}
onDisconnected()
AlertDialog.Builder(this)
.setMessage(message)
.setNeutralButton(android.R.string.ok, null)
.show()
}
}
In Google Play Console I've linked my game with debug keystore SHA-1.
I've checked everythin mentioned in Troubleshooting guide, but I still get this message again and again.
Does someone faced this issue? Any ideas how to debug it?
EDIT:
I found that it actually logs me in - if I restart game, method signInSilently() will be successful. However, it still shows this error 8 when I logout and try to log in manually. Could it be the problem with login activity overlay?
Oh, and I checked api access in Google Play Api Console - it shows that api actually receives my calls and it doesn't mention any errors.
EDIT 2: I've added requestEmail() to GoogleSignInOptions.Builder, and it shows me overlay with access request. However, it still fails in GoogleSignIn.getSignedInAccountFromIntent(intent).getResult(ApiException::class.java) with same error (8 - internal error).
It looks like this bug in Google Play Services 12.2.21:
https://github.com/googlesamples/google-services/issues/358
Google is supposed to be working on a fix for release over the air soon..
it's maybe late but I found the reason. It fixed in my case and I see your code has same problem.
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
...
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
...
}
The intent you passed to the method getSignedInAccountFromIntent() is not the intent that returned by onActivityResult. The intent you passed come from activity, so you need to change it to
val task = GoogleSignIn.getSignedInAccountFromIntent(data)
"data" is the intent returned by onActivityResult
I didn't found the reason of this error, but I found an (ugly) workaround. I noticed, that when I restart game after manual login, even if there was this error, signInSilently() method works fine, which means that API actually authenticate me and fails later. So in catch block I'm checking for status code of error, and, if it's (8 - internal error), I'm requesting last signed in account. If account is present, I assume user to be logged in.
It's really dirty but I'm out of ideas.
//onActivityResult
val task = GoogleSignIn.getSignedInAccountFromIntent(intent)
try {
val account = task.getResult(ApiException::class.java)
onSuccess(account)
} catch (apiException: ApiException) {
val acc = GoogleSignIn.getLastSignedInAccount(context)
if (apiException.statusCode == 8 && acc != null && acc.email != null) {
onSuccess(account)
} else {
onFail(apiException)
}
}
I have a client with that error. Only ONE! With a Galaxy S9. Nothing happens when clicking on the Sign In button (startActivityForResult -> GoogleSignIn.getClient.getSignInIntent)
I need to get google+ signIn tokenId.
Here is my code:
var mGSO = GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(WEB_CLIENT_ID)//from developer console
.requestEmail()
.build()
mGoogleApiClient = GoogleApiClient.Builder(mActivity)
.enableAutoManage(mActivity, this)
.addApi(Auth.GOOGLE_SIGN_IN_API, mGSO)
.build()
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
var tokenId = result.signInAccount.idToken
}
So I successfully get tokenId, but when I try to check it here (https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=) I receive message:
{
"error": "invalid_token",
"error_description": "Invalid Value"
}
Token the same every time I try to get it!
What is happening?
Any idea how to fix this?
UPDATE
found this issue: https://github.com/PhilipGarnero/django-rest-framework-social-oauth2/issues/61
I was using the wrong google token from my sign-in on iOS. I
originally used user.authentication.idToken which is wrong, and will
not work.
The correct token is user.authentication.accessToken.
but i cant find any similar accessToken at GoogleSignInResult object....
UPDATE 2
i am using debug apk.
here is my button click code:
fun onGooglePlusClicked(v: View) {
val signInIntent = Auth.GoogleSignInApi.getSignInIntent(mGoogleApiClient)
mActivity?.startActivityForResult(signInIntent, GOOGLE_SIGN_IN)
}
Very important thing
Google needs to update the documentation, because it is misleading.
Either you are on iOS, or Android, you have to send the accessToken to the backend and not the idToken
You can get the accessToken from user object (e.g. val accessToken = user.authentication.accessToken)
For example, if you want to get user info, try this GET request:
https://www.googleapis.com/oauth2/v3/tokeninfo?access_token={access_token}
The answer was founded here:
https://developers.google.com/identity/protocols/CrossClientAuth
key words: GoogleAuthUtil.getToken()
so, here is my updated code:
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
val result = Auth.GoogleSignInApi.getSignInResultFromIntent(data)
Observable.create(Observable.OnSubscribe<String> {
var **accessTokent** = GoogleAuthUtil.getToken(mActivity!!, result.signInAccount.account, "oauth2:" + Scopes.PLUS_LOGIN)
//send token to server
})
.subscribeOn(Schedulers.io())
.observeOn(AndroidSchedulers.mainThread())
.subscribe()
}
hope this will help someone :)
Answer in 2021:
I've had the same problem.
For me clearing app data completely solved the issue.
Seemed like an old expired token got stuck.
Also the id token should be verified here
https://oauth2.googleapis.com/tokeninfo?id_token=
In my case, I was testing this in Unity and I copied the idToken value that I printed in logcat. Turns out, there is some character or size limit (1024 bytes?) for a line in either adb logcat or Unity's Debug.Log() method. So the printed token value was getting truncated. What I did then for testing was that I copied the token value to clipboard during runtime and then checked again with the tokeninfo endpoint https://oauth2.googleapis.com/tokeninfo?id_token= and it was accepted.