Android: Wie stelle ich Passcode / PIN nur für meine App ein?
Ich arbeite an einer App, in der ich die Sicherheitsfunktion festlegen muss, indem ich Passcode / Passwort / PIN für den Benutzer einstelle, sodass die App jedes Mal, wenn er die App aus dem Hintergrund öffnet, nach Passwort / Passcode / PIN fragt. Ich habe ein paar Artikel / Lösungen wie diese gelesen, aber sie haben mir nicht geholfen. Dieselbe Funktionalität, die wir in normalen Banking-Apps gefunden haben, bei denen beim Öffnen einer App nach Passcode / Fingerabdruck gefragt wird.
Ich habe bereits die Logik eingerichtet, um den Passcode / die PIN in einer gemeinsamen Einstellung zu speichern, bin mir jedoch nicht sicher, wann ich danach fragen soll. Ich weiß, dass wir den Begrüßungsbildschirm nicht durch Passcode- / PIN-Aktivitäten ersetzen können, da der Benutzer manchmal auf dem HomeScreen / der MainActivity der App die Home-Taste drückt und beim erneuten Öffnen der App aus den letzten Apps nach der App nach Passcode / PIN fragen sollte, um den Vorgang fortzusetzen App verwenden.
Jede Hilfe wäre dankbar.
Antworten
Dies ist eine interessante Frage, ich werde meine Gedanken zu dieser Frage teilen und auch eine Lösung geben.
Terminologie:
App- Sperrtyp : Ein generischer Name für PIN / PIN-Code / Passwort / Passcode usw. (im folgenden Abschnitt werde ich den PIN-Namen zur Demonstration verwenden).
PinActivity: Ein Bildschirm, auf dem Benutzer ihre PIN eingeben, um sich selbst zu überprüfen
Geschichte:
Bei Apps, bei denen Benutzer eine PIN eingeben müssen, möchten sie normalerweise sicherstellen, dass vertrauliche Informationen nicht von anderen Personen verloren gehen oder gestohlen werden. Daher werden wir App-Aktivitäten in zwei Gruppen einteilen.
Normale Aktivitäten: Enthält keine vertraulichen Informationen, normalerweise bevor sich Benutzer bei der App angemeldet haben, wie z. B. SplashActivity, LoginActivity, RegistrationActivity, PinActivity usw.
Gesicherte Aktivitäten: Enthalten vertrauliche Informationen, normalerweise nachdem sich Benutzer angemeldet haben, z. B. MainActivity, HomeActivity, UserInfoActivity usw.
Bedingungen:
Für gesicherte Aktivitäten müssen wir sicherstellen, dass Benutzer immer ihre PIN eingeben, bevor sie den Inhalt anzeigen, indem wir die PinActivity anzeigen. Diese Aktivität wird in den folgenden Szenarien gezeigt:
[1] Wenn Benutzer eine gesicherte Aktivität öffnen, bilden Sie eine normale Aktivität, z. B. von SplashActivity zu MainActivity
[2] Wenn Benutzer eine gesicherte Aktivität öffnen, indem sie auf Benachrichtigungen tippen, z. B. auf eine Benachrichtigung, um MainActivity zu öffnen
[3] Wenn Benutzer auf dem Bildschirm "Letzte" auf die App tippen
[4] Wenn die App eine gesicherte Aktivität von einem anderen Ort aus startet, z. B. von Diensten, Rundfunkempfängern usw.
Implementierung:
Für den Fall [1] [2] und [4] fügen wir vor Beginn einer gesicherten Aktivität der ursprünglichen Absicht ein Extra hinzu. Ich werde eine Datei mit dem Namen IntentUtils.kt erstellen
IntentUtils.kt
const val EXTRA_IS_PIN_REQUIRED = "EXTRA_IS_PIN_REQUIRED"
fun Intent.secured(): Intent {
return this.apply {
putExtra(EXTRA_IS_PIN_REQUIRED, true)
}
}
Verwenden Sie diese Klasse für normale Aktivitäten, Benachrichtigungen, Dienste usw.
startActivity(Intent(this, MainActivity::class.java).secured())
Für Fall [3] werde ich 2 APIs verwenden:
ProcessLifecycleOwner : Um festzustellen, ob die App in den Hintergrund wechselt. Ein typisches Szenario ist, wenn Benutzer auf ihren Geräten auf die Start- / Menütaste klicken.
ActivityLifecycleCallbacks : Um festzustellen, ob eine Aktivität wieder aufgenommen wird, verlassen Sie sich auf die onActivityResumed- Methode (Aktivitätsmethode) .
Zuerst erstelle ich eine Basisaktivität, jede normale Aktivitis muss von dieser Klasse ausgehen
BaseActivity.kt
open class BaseActivity : AppCompatActivity() {
// This method indicates that a pin is required if
// users want to see the content inside.
open fun isPinRequired() = false
}
Zweitens erstelle ich eine gesicherte Aktivität, alle gesicherten Aktivitäten müssen von dieser Klasse ausgehen
SecuredActivity.kt
open class SecuredActivity : BaseActivity() {
override fun isPinRequired() = true
// This is useful when launch a secured activity with
// singleTop, singleTask, singleInstance launch mode
override fun onNewIntent(intent: Intent?) {
super.onNewIntent(intent)
setIntent(intent)
}
}
Drittens erstelle ich eine Klasse, die sich von der Anwendung aus erstreckt. Die gesamte Logik befindet sich in dieser Klasse
MyApplication.kt
class MyApplication : Application() {
private var wasEnterBackground = false
override fun onCreate() {
super.onCreate()
registerActivityLifecycleCallbacks(ActivityLifecycleCallbacksImpl())
ProcessLifecycleOwner.get().lifecycle.addObserver(LifecycleObserverImpl())
}
private fun showPinActivity() {
startActivity(Intent(this, PinActivity::class.java))
}
inner class LifecycleObserverImpl : LifecycleObserver {
@OnLifecycleEvent(Lifecycle.Event.ON_STOP)
fun onEnterBackground() {
wasEnterBackground = true
}
}
inner class ActivityLifecycleCallbacksImpl : ActivityLifecycleCallbacks {
override fun onActivityResumed(activity: Activity) {
val baseActivity = activity as BaseActivity
if (!wasEnterBackground) {
// Handle case [1] [2] and [4]
val removed = removeIsPinRequiredKeyFromActivity(activity)
if (removed) {
showPinActivity()
}
} else {
// Handle case [3]
wasEnterBackground = false
if (baseActivity.isPinRequired()) {
removeIsPinRequiredKeyFromActivity(activity)
showPinActivity()
}
}
}
private fun removeIsPinRequiredKeyFromActivity(activity: Activity): Boolean {
val key = EXTRA_IS_PIN_REQUIRED
if (activity.intent.hasExtra(key)) {
activity.intent.removeExtra(key)
return true
}
return false
}
override fun onActivityCreated(activity: Activity, savedInstanceState: Bundle?) {}
override fun onActivityStarted(activity: Activity) {}
override fun onActivityPaused(activity: Activity) {}
override fun onActivitySaveInstanceState(activity: Activity, outState: Bundle) {}
override fun onActivityStopped(activity: Activity) {}
override fun onActivityDestroyed(activity: Activity) {}
}
}
Fazit:
Diese Lösung funktioniert in den zuvor genannten Fällen, aber ich habe die folgenden Szenarien nicht getestet:
- Beim Start hat eine gesicherte Aktivität den Startmodus singleTop | singleTask | singleInstance
- Wenn die Anwendung vom System bei geringem Arbeitsspeicher beendet wird
- Andere Szenarien, denen jemand begegnen könnte (wenn ja, lassen Sie es mich bitte im Kommentarbereich wissen).