我有下面的代码试图与短信令牌,我得到令牌代码,但一旦我发送它在短信,我没有回应!
MainActivity。kt
package com.sms
import android.app.PendingIntent
import android.content.Intent
import android.os.Bundle
import android.telephony.SmsManager
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import androidx.compose.ui.tooling.preview.Preview
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.auth.api.phone.SmsRetrieverClient
import com.sms.ui.theme.SmsTheme
class MainActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
// val smsManager: SmsManager = SmsManager.getDefault()
val smsManager: SmsManager = getSystemService(SmsManager::class.java)
val appSmsToken = smsManager.createAppSpecificSmsToken(createSmsTokenPendingIntent())
print(appSmsToken)
setContent {
SmsTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Greeting(appSmsToken)
}
}
}
}
private fun createSmsTokenPendingIntent(): PendingIntent? {
return PendingIntent.getActivity(
this, 1234,
Intent(this, SmsTokenResultVerificationActivity::class.java),
PendingIntent.FLAG_IMMUTABLE or PendingIntent.FLAG_UPDATE_CURRENT) // setting the mutability flag
}
}
@Composable
fun Greeting(name: String) {
Text(text = "Token is: $name")
}
@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
SmsTheme {
Greeting("Android")
}
}
和SmsTokenResultVerificationActivity。kt是:
package com.sms
import android.os.Bundle
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.material.MaterialTheme
import androidx.compose.material.Surface
import androidx.compose.material.Text
import androidx.compose.runtime.Composable
import androidx.compose.ui.Modifier
import com.sms.ui.theme.SmsTheme
class SmsTokenResultVerificationActivity : ComponentActivity() {
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContent {
SmsTheme {
// A surface container using the 'background' color from the theme
Surface(modifier = Modifier.fillMaxSize(), color = MaterialTheme.colors.background) {
Greeting("Welcome")
}
}
}
}
@Composable
fun Greeting(name: String) {
Text(text = "hi: $name")
}
}
###作为另一个选择,我发现使用SMS retriever API in Android
could solve it but I still interested但我还是有兴趣用Token
as i want my app to depend on the user device因为我想让我的应用依赖于用户
device
token rather than the app
令牌而不是app
token.
BaseApplication。kt
package com.shishirthedev.smsretriverapi
import android.app.Application
import android.util.Log
import android.widget.Toast
class BaseApplication : Application() {
private val TAG = BaseApplication::class.java.simpleName
override fun onCreate() {
super.onCreate()
// Generate Hash Key >>>>>
val appSignatureHashHelper = AppSignatureHashHelper(this)
Log.e(TAG, "HashKey: " + appSignatureHashHelper.appSignatures[0])
var msg = "HashKey: " + appSignatureHashHelper.appSignatures[0]
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
// Storing data into SharedPreferences
val sharedPreferences = getSharedPreferences("MySharedPref", MODE_PRIVATE)
// Creating an Editor object to edit(write to the file)
val myEdit = sharedPreferences.edit()
// Storing the key and its value as the data fetched from edittext
myEdit.putString("token", appSignatureHashHelper.appSignatures[0])
// myEdit.putInt("age", age.getText().toString().toInt())
// Once the changes have been made,
// we need to commit to apply those changes made,
// otherwise, it will throw an error
myEdit.commit()
}
}
AppSignatureHashHelper。kt
package com.shishirthedev.smsretriverapi
import android.annotation.TargetApi
import android.content.Context
import android.content.ContextWrapper
import android.content.pm.PackageManager
import android.util.Base64
import android.util.Log
import java.nio.charset.StandardCharsets
import java.security.MessageDigest
import java.security.NoSuchAlgorithmException
import java.util.*
class AppSignatureHashHelper(context: Context?) :
ContextWrapper(context) {// Get all package details
/**
* Get all the app signatures for the current package
*
* @return
*/
val appSignatures: ArrayList<String>
get() {
val appSignaturesHashs = ArrayList<String>()
try {
// Get all package details
val packageName = packageName
val packageManager = packageManager
val signatures = if (android.os.Build.VERSION.SDK_INT >= android.os.Build.VERSION_CODES.P) {
packageManager.getPackageInfo(
packageName,
PackageManager.GET_SIGNING_CERTIFICATES
).signingInfo.apkContentsSigners
} else {
TODO("VERSION.SDK_INT < P")
}
for (signature in signatures) {
val hash = hash(packageName, signature.toCharsString())
if (hash != null) {
appSignaturesHashs.add(String.format("%s", hash))
}
}
} catch (e: Exception) {
Log.e(TAG, "Package not found", e)
}
return appSignaturesHashs
}
companion object {
val TAG = AppSignatureHashHelper::class.java.simpleName
private const val HASH_TYPE = "SHA-256"
const val NUM_HASHED_BYTES = 9
const val NUM_BASE64_CHAR = 11
@TargetApi(19)
private fun hash(packageName: String, signature: String): String? {
val appInfo = "$packageName $signature"
try {
val messageDigest = MessageDigest.getInstance(HASH_TYPE)
messageDigest.update(appInfo.toByteArray(StandardCharsets.UTF_8))
var hashSignature = messageDigest.digest()
// truncated into NUM_HASHED_BYTES
hashSignature = Arrays.copyOfRange(hashSignature, 0, NUM_HASHED_BYTES)
// encode into Base64
var base64Hash =
Base64.encodeToString(hashSignature, Base64.NO_PADDING or Base64.NO_WRAP)
base64Hash = base64Hash.substring(0, NUM_BASE64_CHAR)
return base64Hash
} catch (e: NoSuchAlgorithmException) {
Log.e(TAG, "No Such Algorithm Exception", e)
}
return null
}
}
}
SMSReceiver。kt”
import android.content.BroadcastReceiver
import android.content.Context
import android.content.Intent
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.google.android.gms.common.api.CommonStatusCodes
import com.google.android.gms.common.api.Status
import java.util.regex.Pattern
class SMSReceiver : BroadcastReceiver() {
private var otpListener: OTPReceiveListener? = null
fun setOTPListener(otpListener: OTPReceiveListener?) {
this.otpListener = otpListener
}
override fun onReceive(context: Context, intent: Intent) {
if (intent.action == SmsRetriever.SMS_RETRIEVED_ACTION) {
val extras = intent.extras
val status = extras!![SmsRetriever.EXTRA_STATUS] as Status?
when (status!!.statusCode) {
CommonStatusCodes.SUCCESS -> {
val sms = extras[SmsRetriever.EXTRA_SMS_MESSAGE] as String?
sms?.let {
// val p = Pattern.compile("[0-9]+") check a pattern with only digit
val p = Pattern.compile("\\d+")
val m = p.matcher(it)
if (m.find()) {
val otp = m.group()
if (otpListener != null) {
otpListener!!.onOTPReceived(otp)
}
}
}
}
}
}
}
interface OTPReceiveListener {
fun onOTPReceived(otp: String?)
}
}
MainActivity。kt
package com.shishirthedev.smsretriverapi
import android.content.IntentFilter
import android.os.Bundle
import android.widget.TextView
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import com.google.android.gms.auth.api.phone.SmsRetriever
import com.shishirthedev.smsretriverapi.SMSReceiver.OTPReceiveListener
class MainActivity : AppCompatActivity() {
private var intentFilter: IntentFilter? = null
private var smsReceiver: SMSReceiver? = null
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
var token = findViewById<TextView>(R.id.textView)
// Retrieving the value using its keys the file name
// must be same in both saving and retrieving the data
val sh = getSharedPreferences("MySharedPref", MODE_PRIVATE)
// The value will be default as empty string because for
// the very first time when the app is opened, there is nothing to show
val t = sh.getString("token", "")
// val a = sh.getInt("age", 0)
// We can then use the data
token.text = t
// age.setText(a.toString())
// Init Sms Retriever >>>>
initSmsListener()
initBroadCast()
}
private fun initBroadCast() {
intentFilter = IntentFilter(SmsRetriever.SMS_RETRIEVED_ACTION)
smsReceiver = SMSReceiver()
smsReceiver?.setOTPListener(object : OTPReceiveListener {
override fun onOTPReceived(otp: String?) {
showToast("OTP Received: $otp")
}
})
}
private fun initSmsListener() {
val client = SmsRetriever.getClient(this)
client.startSmsRetriever()
}
override fun onResume() {
super.onResume()
registerReceiver(smsReceiver, intentFilter)
}
override fun onPause() {
super.onPause()
unregisterReceiver(smsReceiver)
}
override fun onDestroy() {
super.onDestroy()
smsReceiver = null
}
private fun showToast(msg: String?) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show()
}
}
清单
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.shishirthedev.smsretriverapi">
<application
android:name=".BaseApplication"
android:allowBackup="true"
android:icon="@mipmap/ic_launcher"
android:label="@string/app_name"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true"
android:theme="@style/Theme.SmsRetriverAPi">
<activity android:name=".MainActivity">
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
</application>
</manifest>
构建。gradle(模块)
plugins {
id 'com.android.application'
id 'kotlin-android'
}
android {
compileSdkVersion 30
buildToolsVersion "29.0.3"
defaultConfig {
applicationId "com.shishirthedev.smsretriverapi"
minSdkVersion 21
targetSdkVersion 30
versionCode 1
versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
}
buildTypes {
release {
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
}
compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8
}
kotlinOptions {
jvmTarget = '1.8'
}
}
dependencies {
implementation "org.jetbrains.kotlin:kotlin-stdlib:$kotlin_version"
implementation 'androidx.core:core-ktx:1.3.2'
implementation 'androidx.appcompat:appcompat:1.2.0'
implementation 'com.google.android.material:material:1.2.1'
implementation 'androidx.constraintlayout:constraintlayout:2.0.4'
testImplementation 'junit:junit:4.+'
androidTestImplementation 'androidx.test.ext:junit:1.1.1'
androidTestImplementation 'androidx.test.espresso:espresso-core:3.3.0'
implementation 'com.google.android.gms:play-services-auth:19.0.0'
implementation 'com.google.android.gms:play-services-auth-api-phone:17.5.0'
}
“构建。gradle(项目)
// Top-level build file where you can add configuration options common to all sub-projects/modules.
buildscript {
ext.kotlin_version = "1.4.10"
repositories {
google()
jcenter()
}
dependencies {
classpath 'com.android.tools.build:gradle:4.1.2'
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
// NOTE: Do not place your application dependencies here; they belong
// in the individual module build.gradle files
}
}
allprojects {
repositories {
google()
jcenter()
}
}
task clean(type: Delete) {
delete rootProject.buildDir
}
信贷去
SHISHIR