App freischalten nach einmaliger Pin-eingabe?

  • Antworten:17
aphi
  • Forum-Beiträge: 23

07.08.2016, 09:55:32 via Website

Hallo,
Ich sitze nun schon seit Stunden an einem Problem und weiß keine Lösung mehr.
Die App, die ich programmiere, soll nur einmalig, nachdem man sie installiert hat , eine Pin abfragen, um nur Leuten auf die App Zugriff zu gewähren, die die Pin haben.
Ich bin schon soweit, dass man mit der Pin reinkommt und bei einer falschen Pin nicht.
Aber ich verzweifle daran, die Pin Abfrage nur einmal zu machen, und nicht bei jedem Start.
Ich kann mit SharedPreferences feststellen, ob es das erste Mal ist, aber ich muss gleichzeitig noch abfragen, ob die Pin eingegeben wurde, weil sonst kann man, ohne die Pin einzugeben, die App einfach beenden und neu starten und die Pin wird nicht abgefragt, obwohl man sie noch nicht eingegeben hat.

Das ist meine Unlock.java

package intern.csg_germering.de.csg_info;
import android.annotation.SuppressLint;
import android.content.Context;
import android.content.Intent;
import android.content.SharedPreferences;
import android.graphics.Bitmap;
import android.os.AsyncTask;
import android.os.Bundle;
import android.os.Handler;
import android.view.View;
import android.support.v7.app.AppCompatActivity;
import android.support.v7.widget.Toolbar;
import android.view.inputmethod.InputMethodManager;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import android.widget.Button;
import android.widget.EditText;
import android.widget.RelativeLayout;
import android.widget.TextView;
import android.widget.Toast;

import java.util.Objects;
import java.util.Observable;

import intern.csg_germering.de.csg_info.Main;

public class Unlock extends AppCompatActivity {

    public Button unlockbt;
    public EditText pin;
    public TextView helppin;



    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_unlock);
        unlockbt = (Button) findViewById(R.id.unlockbt);
        pin = (EditText) findViewById(R.id.pin);
        helppin = (TextView) findViewById(R.id.helppin);







    }






    boolean doubleBackToExitPressedOnce = false;

    @SuppressLint("NewApi")
    @Override
    public void onBackPressed() {

        if (doubleBackToExitPressedOnce) {
            this.finishAndRemoveTask();

            return;
        }

        this.doubleBackToExitPressedOnce = true;
        Toast.makeText(this, "Zum Verlassen der Anwendung, 'Zurück' erneut drücken.", Toast.LENGTH_SHORT).show();

        new Handler().postDelayed(new Runnable() {

            @Override
            public void run() {
                doubleBackToExitPressedOnce=false;
            }
        }, 2000);

    }



    @SuppressLint("NewApi")
    public void unlock(View view){


        String enteredPin = (String) pin.getEditableText().toString();

        String PIN = "0000";
        if (Objects.equals(PIN, enteredPin)){

            startActivity(new Intent(Unlock.this, Main.class));
            Main.permissionOk = true;
            Toast.makeText(this, "Freigeschaltet!" , Toast.LENGTH_SHORT).show();




        }
        else {

            Toast.makeText(this, "Falsche Pin." , Toast.LENGTH_SHORT).show();
            pin.setText("");



        }

    }
    public void showFAQ(View view) {
        startActivity(new Intent(Unlock.this, about.class));



    }


}

Und hier die "First Time " Abfrage in der Main.java

public SharedPreferences sharedTime = getSharedPreferences(preferences_name,0);

   if (sharedTime.getBoolean("firstTime",true))
    {

        startActivity(new Intent(Main.this, Unlock.class));

        sharedTime.edit().putBoolean("firstTime",false).apply();

    }

Schonmal Danke im Voraus
LG Phillip

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

07.08.2016, 10:07:01 via App

Und was ist das Problem?
Du musst mit einer If prüfen ob es den Key firstTime gibt. (hasKey())

Wenn es den Key gibt und dieser ist false dann hat man sich schon angemeldet. Ansonsten zur pineingabe weiterleiten. Sobald pin erfolgreich eigegeben (reagieren auf Buttonklick o.ä.) dann die Preference auf false setzen und fertig.
Diese Abfrage muss in der onCreate der MainActuvity abgefragt werden.

Und der Sicherheits wegen würde ich die Pin nicht als String überprüfen sondern als Integer parsen und irgendwas berechnen. z.b. Quersumme*x o.ä.

LG Pascal //It's not a bug, it's a feature. :) ;)

aphi

Antworten
aphi
  • Forum-Beiträge: 23

07.08.2016, 10:15:46 via Website

Aber wie kann ich die Preferences Klassenübergreifend machen? Ich muss ja in der Main.java die if Abfrage machen und in der Unlock.java die Preference setzen.

Antworten
aphi
  • Forum-Beiträge: 23

07.08.2016, 10:25:44 via Website

Um die Preference sharedTime von Unlock.java aus zu ändern, muss ich sie in der Main.java static machen, bekomme dann aber den Fehler: "Non-static method "getSharedPreferences " cannot be referenced from a static context" . Wie geht das dann also?

Antworten
swa00
  • Forum-Beiträge: 3.704

07.08.2016, 10:42:01 via Website

Hallo ,

um Klassenübergreiffend mit den Setups zu arbeiten musst du SingleTon anwenden

Entweder in der abgleiteten Klasse von Application oder als Wrapper z.b so
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

public class Setup

{
private static Setup mInstance;
private Context mContext;

private SharedPreferences mMyPreferences;

private Setup(){ }

public static Setup getInstance()
{
    if (mInstance == null) mInstance = new Setup();
    return mInstance;
}

public void Initialize(Activity activity,Context ctxt)
{
    mContext = ctxt;


    mMyPreferences =activity.getSharedPreferences("MYPREFS", Activity.MODE_PRIVATE);
    //mMyPreferences = PreferenceManager.getDefaultSharedPreferences(mContext);
}



///////////////////////////////////////////////////////////////

public String getString (String key,String def)
{

   return  mMyPreferences.getString(key,def);

}
}
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////
////////////////////////////////////////////////////////////

Aufruf -z.b in OnCreate:

 //  Setup initialisieren
    Setup.getInstance().Initialize(this,getApplicationContext());

Value ermitteln :

String val    = Setup.getInstance().getString("mein_key", "Default"));

P.S Sorry für die Formatierung - will nicht so , wie ich möchte

— geändert am 07.08.2016, 11:06:27

Liebe Grüße - Stefan
[ App - Entwicklung ]

aphi

Antworten
Pascal P.
  • Admin
  • Forum-Beiträge: 11.286

07.08.2016, 11:04:09 via App

Ich würde das garnicht so kompliziert machen.
Es gibt doch die Default shared preferences. Die würde ich nutzen. Und die kannst du dir per Get aus beiden Activities holen da es eine Systemkomponente ist.
SharedPreferences pref =PreferenceManager.getDefaultPreferences();
Das in beiden Activities und die Variable pref verweden. Da brauchst du nichts Activity übergreifendes Programmieren.

LG Pascal //It's not a bug, it's a feature. :) ;)

Antworten
swa00
  • Forum-Beiträge: 3.704

07.08.2016, 11:10:55 via Website

@Pascal

Das hatte ich auch zuerst angedacht - ich wollte vermeiden , dass er morgen dann fragt ,
warum er manchmal seine Setups verliert :-)

P.S Dir einen schönen Sonntag auch wenn wir beide bei dem Wetter vor der Kiste sitzen :-)

— geändert am 07.08.2016, 11:12:18

Liebe Grüße - Stefan
[ App - Entwicklung ]

Pascal P.

Antworten
aphi
  • Forum-Beiträge: 23

07.08.2016, 13:49:36 via Website

Ich habe das jetzt mal für meine Bedürfnisse umgeschrieben, weiß aber noch nicht wo ich den SharedPreferences-Editor initialisieren soll, in meiner Setup.java gibt es ja keine onCreate Methode, da es ja ein SingleTon ist. Hier meine Setup.java

package intern.csg_germering.de.csg_info;



import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class Setup

{
    private static Setup mInstance;
    private Context mContext;

    private SharedPreferences mMyPreferences;
    private SharedPreferences.Editor mMyPreferencesEditor;


    public static String preferences_isunlocked;

    private Setup() {
    }

    public static Setup getInstance() {
        if (mInstance == null) mInstance = new Setup();
        return mInstance;
    }

    public void Initialize(Activity activity, Context ctxt) {
        mContext = ctxt;
        mMyPreferencesEditor = mMyPreferences.edit();


        mMyPreferences = activity.getSharedPreferences("unlockedprefsdatei", Activity.MODE_PRIVATE);

    }
    public void setString(String preferences_isunlockedstring) {
        preferences_isunlockedstring = preferences_isunlocked;

        mMyPreferencesEditor.putString("isUnlockedKey", preferences_isunlockedstring);
        mMyPreferencesEditor.apply();

    }


///////////////////////////////////////////////////////////////

    public String getString() {

        return mMyPreferences.getString("isUnlockedKey", "-leer-");

    }
}

Da bekomme ich immer:

Caused by: java.lang.NullPointerException: Attempt to invoke interface method 'android.content.SharedPreferences$Editor android.content.SharedPreferences.edit()' on a null object reference
at intern.csg_germering.de.csg_info.Setup.Initialize(Setup.java:34)

Antworten
swa00
  • Forum-Beiträge: 3.704

07.08.2016, 14:20:11 via Website

Am beste jeweils beim Setter

P.S Nur als Hinweis , Getter und Setter werden aus Performancegründen bei Android ungerne gesehen.
Trotzdem halte ich diese in dem Falle für "praktischer"

///////////////////////////////////////////////////////////////
public void putString (String key,String val)
{
SharedPreferences.Editor e = mMyPreferences.edit();
e.putString(key, val);
e.commit(); (oder apply)
}

— geändert am 07.08.2016, 14:24:45

Liebe Grüße - Stefan
[ App - Entwicklung ]

aphi

Antworten
aphi
  • Forum-Beiträge: 23

07.08.2016, 21:27:19 via Website

Jetzt gibt es keine Fehler mehr, aber es speichert die Variable nicht, d.h. dass jetzt bei jedem starten der app die pin-abfrage aufgerufen wird und nicht nur einmal bei installieren der app.

Antworten
swa00
  • Forum-Beiträge: 3.704

07.08.2016, 21:32:07 via Website

öhm , kann fast nicht sein - poste mal bitte deinen aktuellen code

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten
aphi
  • Forum-Beiträge: 23

07.08.2016, 21:42:08 via Website

Setup.java:

package intern.csg_germering.de.csg_info;

/**
 * Created by Philli on 07.08.2016.
 */

import android.app.Activity;
import android.content.Context;
import android.content.SharedPreferences;
import android.preference.PreferenceManager;

public class Setup

{
    private static Setup mInstance;
    private Context mContext;

    private SharedPreferences mMyPreferences;



    public static String preferences_isunlocked;

    private Setup() {
    }

    public static Setup getInstance() {
        if (mInstance == null) mInstance = new Setup();
        return mInstance;
    }

    public void Initialize(Activity activity, Context ctxt) {
        mContext = ctxt;



        mMyPreferences = activity.getSharedPreferences("unlockedprefsdatei", Activity.MODE_PRIVATE);

    }
    public void setString(String preferences_isunlockedstring) {
        preferences_isunlockedstring = preferences_isunlocked;
        SharedPreferences.Editor e = mMyPreferences.edit();
        e.putString("isUnlockedKey", preferences_isunlockedstring);
        e.apply();

    }


///////////////////////////////////////////////////////////////

    public String getString() {

        return mMyPreferences.getString("isUnlockedKey", "-leer-");

    }
}

Das Setten in der Unlock.java:

if (Objects.equals(PIN, enteredPin)){


        Main.permissionOk = true;
        Toast.makeText(this, "Freigeschaltet!" , Toast.LENGTH_SHORT).show();
        Setup.getInstance().Initialize(this, getApplicationContext());
        Setup.getInstance().setString("true");
        finishAndRemoveTask();


    }
    else {

        Toast.makeText(this, "Falsche Pin." , Toast.LENGTH_SHORT).show();
        pin.setText("");
        Setup.getInstance().Initialize(this, getApplicationContext());
        Setup.getInstance().setString("false");



    }

Das Getten in der Main.java:

Setup.getInstance().Initialize(this, getApplicationContext());
        String unlocked = Setup.getInstance().getString();
        ActivityRegistry.register(this);
        if (unlocked.equals("-leer-") || unlocked.equals("false")){
            startActivity(new Intent(Main.this, Unlock.class));

        }

Antworten
swa00
  • Forum-Beiträge: 3.704

07.08.2016, 22:02:23 via Website

@Aphi

a) Die "Technik" die ich dir vorgeschlagen habe, läuft bei mir auf mehreren Apps problemlos. Sieht auch ganz gut aus ,was du da gemacht hast - ich verstehe allerdings nicht , warum Du in deiner Setupklasse feste Strings als key/value verwendest - die Setup-Klasse ist eher dafür gedacht, sie mehrfach zu verwenden ... aber ist dein Ding :-)
b) Dann fällt mir auf , dass du mehrmals

Setup.getInstance().Initialize(this, getApplicationContext());

benutzt...

Dies solltest du nur EINMAL in der MainActivity tun ...

P.S Kann es sein , dass du viel mit Static Variablen/Klassen arbeitest ? Wenn ja , dann das bitte dringend abstellen.

— geändert am 07.08.2016, 22:21:37

Liebe Grüße - Stefan
[ App - Entwicklung ]

aphi

Antworten
aphi
  • Forum-Beiträge: 23

08.08.2016, 07:57:22 via Website

@swa00

Danke für deine Hilfe! Jetzt funktioniert es.
Kann es vielleicht sein, dass mit

 Setup.getInstance().Initialize(this, getApplicationContext()); 

eine neue Datei generiert wird, die die alte unlockedprefsdatei überschreibt? weil mit Initialize wird ja

mMyPreferences = activity.getSharedPreferences("unlockedprefsdatei", Activity.MODE_PRIVATE); 

ausgeführt?

P.S. ich habe in der Setup.java einen festen String gemacht, weil ich sie nur einmal brauche. Aber in anderen apps ist sie sicher auch nützlich ... :)

Antworten
swa00
  • Forum-Beiträge: 3.704

08.08.2016, 08:26:03 via Website

@Aphi

Unter Java resp Android ist das Verwenden von Globalen Variablen ein wenig anders , als z.b. bei C/C++, weshalb ich dir diesen Artikel als Verständniss zum Lesen gebe :-)

https://androidresearch.wordpress.com/2012/03/22/defining-global-variables-in-android/

Und bezüglich der Static Variablen steht da ein ganz ganz wichtiger Abschnitt drin :

You may believe that when a static variable is initialized it stays so for the entire life of the application, however this does not seem to be true everytime. Sometimes, there are situations when some static variables bound to activities happens to be uninitialized even they have been initialized.

Auf deutsch : Eine statisch verwendete und gesetzte Variable kann je nach Situation trotzdem ungültig sein. Also ein Spiel mit dem Feuer (Try & Hope)

— geändert am 08.08.2016, 08:35:16

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten
aphi
  • Forum-Beiträge: 23

08.08.2016, 08:31:05 via Website

Ok, danke!

Antworten
aphi
  • Forum-Beiträge: 23

08.08.2016, 08:32:08 via Website

Heißt das, dass static Variablen auch "spinnen" können?

Antworten
swa00
  • Forum-Beiträge: 3.704

08.08.2016, 08:40:34 via Website

Wenn Du es so einfach ausdrücken möchtest : Ja :-)

— geändert am 08.08.2016, 13:11:58

Liebe Grüße - Stefan
[ App - Entwicklung ]

Antworten