• Najnowsze pytania
  • Bez odpowiedzi
  • Zadaj pytanie
  • Kategorie
  • Tagi
  • Zdobyte punkty
  • Ekipa ninja
  • IRC
  • FAQ
  • Regulamin
  • Książki warte uwagi

Klient serwisu www na Android

Object Storage Arubacloud
+1 głos
103 wizyt
pytanie zadane 6 stycznia 2023 w Android, Swift, Symbian przez bzc0fq Nowicjusz (130 p.)

Dobry wieczór,

Potrzebuję napisać klienta na Androida, który będzie wymieniał dane z bazą udostępnianą przez skrypty PHP. Nie mam żadnego doświadczenia w programowaniu Androida. Mam ponad 20 letnie doświadczenie w IT, ale jako administrator - nie jako programista, chociaż programowałem w trochę Javie i PHP.

Nie chcę tego zlecać, bo jest to po prostu moje hobby i czuję się na siłach powoli krok po kroku ogarnąć temat.

Wstępne założenia to:

  1. Klient będzie napisany w Javie (Android Studio)
  2. Klient będzie używać Retrofit2 do łączenia się ze skryptami php przez https.
  3. Skrypty PHP będą komunikowały się z istniejącą bazą aplikacji webowej.

Próbuję ogarnąć temat logowania do bazy i częściowo mi się udało, ale nie do końca. Korzystałem z tego tutoriala, i jestem w stanie się zalogować, ale nie wiem dlaczego nie mogę przejść do activity_welcome... widzę że Toast 'Zalogowany' jest wyświetlany bez względu na poprawne (lub nie) zalogowanie, choć z logów widzę kiedy prawidłowe zmienne są ustawiane po zalogowaniu.

Mój kod LoginActivity wygląda tak:

public class LoginActivity extends AppCompatActivity {

    private EditText etEmail, etPass;
    private Button btnlogin;
    private TextView tvreg;
    private PreferenceHelper preferenceHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_login);

        preferenceHelper = new PreferenceHelper(this);

        etEmail = (EditText) findViewById(R.id.etemail);
        etPass = (EditText) findViewById(R.id.etpassword);

        btnlogin = (Button) findViewById(R.id.btn);
        tvreg = (TextView) findViewById(R.id.tvreg);

        tvreg.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(LoginActivity.this, MainActivity.class);
                startActivity(intent);
                LoginActivity.this.finish();
            }
        });

        btnlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                loginUser();
            }
        });
    }

    private void loginUser() {

        final String email = etEmail.getText().toString().trim();
        final String password = md5(etPass.getText().toString().trim());

        /*
        HttpLoggingInterceptor interceptor = new HttpLoggingInterceptor();
        interceptor.level(HttpLoggingInterceptor.Level.BODY);
        OkHttpClient client = new OkHttpClient.Builder().addInterceptor(interceptor).build();
        */

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(LoginInterface.LOGINURL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

        LoginInterface api = retrofit.create(LoginInterface.class);

        Call<String> call = api.getUserLogin(email,password);

        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Log.i("Responsestring", response.body().toString());

                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        Toast.makeText(getApplicationContext(), "Zalogowano", Toast.LENGTH_LONG).show();

                        Log.i("onSuccess", response.body().toString());

                        String jsonresponse = response.body().toString();
                        parseLoginData(jsonresponse);

                    } else {
                        Toast.makeText(getApplicationContext(), "Błąd logowania", Toast.LENGTH_LONG).show();

                        Log.i("onEmptyResponse", "Returned empty response");
                    }
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {

            }
        });

    }

    private void parseLoginData(String response){
        try {
            JSONObject jsonObject = new JSONObject(response);
            if (jsonObject.getString("status").equals("true")) {

                saveInfo(response);

                Toast.makeText(LoginActivity.this, "Login Successfully!", Toast.LENGTH_SHORT).show();
                Intent intent = new Intent(LoginActivity.this,WelcomeActivity.class);
                intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
                startActivity(intent);
                this.finish();
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }

    }

    private void saveInfo(String response){

        preferenceHelper.putIsLogin(true);
        try {
            JSONObject jsonObject = new JSONObject(response);
            if (jsonObject.getString("status").equals("true")) {
                JSONArray dataArray = jsonObject.getJSONArray("data");
                for (int i = 0; i < dataArray.length(); i++) {

                    JSONObject dataobj = dataArray.getJSONObject(i);
                    preferenceHelper.putName(dataobj.getString("name"));
                    preferenceHelper.putHobby(dataobj.getString("hobby"));
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


    public String md5(String md5) {
        try {
            java.security.MessageDigest md = java.security.MessageDigest.getInstance("MD5");
            byte[] array = md.digest(md5.getBytes("UTF-8"));
            StringBuffer sb = new StringBuffer();
            for (int i = 0; i < array.length; ++i) {
                sb.append(Integer.toHexString((array[i] & 0xFF) | 0x100).substring(1,3));
            }
            return sb.toString();
        } catch (java.security.NoSuchAlgorithmException e) {
        } catch(UnsupportedEncodingException ex){
        }
        return null;
    }

}

 

kod LoginInterface wyglada tak:

public interface LoginInterface {

    String LOGINURL = "https://xxxxx.pl/xxx/php/";
    @FormUrlEncoded
    @POST("login.php")
    Call<String> getUserLogin(
            @Field("email") String uname,
            @Field("password") String password
    );
}

 

kod MainActivity załączam poniżej:

public class MainActivity extends AppCompatActivity {

    private EditText etname, ethobby, etusername, etpassword;
    private Button btnregister;
    private TextView tvlogin;
    private PreferenceHelper preferenceHelper;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        preferenceHelper = new PreferenceHelper(this);

        if(preferenceHelper.getIsLogin()){
            Intent intent = new Intent(MainActivity.this,WelcomeActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.finish();
        }

        etname = (EditText) findViewById(R.id.etname);
        ethobby = (EditText) findViewById(R.id.ethobby);
        etusername = (EditText) findViewById(R.id.etemail);
        etpassword = (EditText) findViewById(R.id.etpassword);

        btnregister = (Button) findViewById(R.id.btn);
        tvlogin = (TextView) findViewById(R.id.tvlogin);

        tvlogin.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent intent = new Intent(MainActivity.this,LoginActivity.class);
                startActivity(intent);
                MainActivity.this.finish();
            }
        });

        btnregister.setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                registerMe();
            }
        });

    }

    private void registerMe() {

        final String name = etname.getText().toString();
        final String hobby = ethobby.getText().toString();
        final String username = etusername.getText().toString();
        final String password = etpassword.getText().toString();

        Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(RegisterInterface.REGIURL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

        RegisterInterface api = retrofit.create(RegisterInterface.class);

        Call<String> call = api.getUserRegi(name,hobby,username,password);

        call.enqueue(new Callback<String>() {
            @Override
            public void onResponse(Call<String> call, Response<String> response) {
                Log.i("Responsestring", response.body().toString());
                //Toast.makeText()
                if (response.isSuccessful()) {
                    if (response.body() != null) {
                        Log.i("onSuccess", response.body().toString());

                        String jsonresponse = response.body().toString();
                        try {
                            parseRegData(jsonresponse);
                        } catch (JSONException e) {
                            e.printStackTrace();
                        }

                    } else {
                        Log.i("onEmptyResponse", "Returned empty response");//Toast.makeText(getContext(),"Nothing returned",Toast.LENGTH_LONG).show();
                    }
                }
            }

            @Override
            public void onFailure(Call<String> call, Throwable t) {

            }
        });
    }

    private void parseRegData(String response) throws JSONException {

        JSONObject jsonObject = new JSONObject(response);
        if (jsonObject.optString("status").equals("true")){

            saveInfo(response);

            Toast.makeText(MainActivity.this, "Registered Successfully!", Toast.LENGTH_SHORT).show();
            Intent intent = new Intent(MainActivity.this,WelcomeActivity.class);
            intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK | Intent.FLAG_ACTIVITY_NEW_TASK);
            startActivity(intent);
            this.finish();
        }else {

            Toast.makeText(MainActivity.this, jsonObject.getString("message"), Toast.LENGTH_SHORT).show();
        }
    }

    private void saveInfo(String response){

        preferenceHelper.putIsLogin(true);
        try {
            JSONObject jsonObject = new JSONObject(response);
            if (jsonObject.getString("status").equals("true")) {
                JSONArray dataArray = jsonObject.getJSONArray("data");
                for (int i = 0; i < dataArray.length(); i++) {

                    JSONObject dataobj = dataArray.getJSONObject(i);
                    preferenceHelper.putName(dataobj.getString("name"));
                    preferenceHelper.putHobby(dataobj.getString("hobby"));
                }
            }
        } catch (JSONException e) {
            e.printStackTrace();
        }
    }


}

Czy mógłyby prosić o podpowiedź co jest nie tak w kodzie jak również o informację w jaki sposób mogę sprawdzić jaki dokładnie pełny URL jest wysyłany POSTem do serwera?

Dziękuję i pozdrawiam w nowym roku!

1 odpowiedź

0 głosów
odpowiedź 6 stycznia 2023 przez Wiciorny Ekspert (269,510 p.)
Retrofit retrofit = new Retrofit.Builder()
                .baseUrl(LoginInterface.LOGINURL)
                .addConverterFactory(ScalarsConverterFactory.create())
                .build();

nie widzę ustawienia klienta Http, potem na którym masz utworzyć instancje interfejsu 
 

OkHttpClient.Builder httpClient = new OkHttpClient.Builder();
Retrofit retrofit = new Retrofit.Builder()
  .baseUrl("https://api.github.com/")
  .addConverterFactory(GsonConverterFactory.create())
  .client(httpClient.build())
  .build();

i następnie wtedy to klient ma być użytkownikiem interfejsu
 

  RegisterInterface api = retrofit.getRetrofitClient().create(RegisterInterface.class);


Jeszcze patrz tu:https://stackoverflow.com/questions/66854752/how-to-use-post-data-in-android-studio-for-login-java-to-php
I upewnij się, że  poziom plików nie jest zagnieżdzony, gdyż odwołujesz się bezpośrednio do   @POST("login.php")
Bez konkretnej ściezki/katalogu. 

komentarz 6 stycznia 2023 przez bzc0fq Nowicjusz (130 p.)

Dzięki za szybką odpowiedź...

nie znam się na Javie i programowaniu ale wydaje mi się że ścieżkę podbiera sobie z .baseUrl(LoginInterface.LOGINURL) który wskazuje na zagnieżdżony katalog i jest zdefiniowany tutaj:

public interface LoginInterface {
    String LOGINURL = "https://xxxxx.pl/xxx/php/";
    @FormUrlEncoded
    @POST("login.php")
    Call<String> getUserLogin(
            @Field("email") String uname,
            @Field("password") String password
    );
}

Jakby to nie działało to by nie odpalał skryptu login.php który właśnie wyciąga z bazy informacje, które są pokazane w logu np. Imię i Nazwisko: Jan Kowalski. Jak podam złe hasło to danych osobowych nie ma - czyli ta część działa chyba OK.

Ale wydaje mi się że tu jest więcej bugów niż tylko ten jeden. Zerknij proszę na loga...

2023-01-06 22:01:26.854 4003-4003/pl.xxxx.xxx I/ViewRootImpl@ba2c0c2[LoginActivity]: ViewPostIme pointer 1
2023-01-06 22:01:26.872 4003-5390/pl.xxxx.xxx D/TrafficStats: tagSocket(112) with statsTag=0xffffffff, statsUid=-1
2023-01-06 22:01:27.417 4003-4003/pl.xxxx.xxx I/Responsestring: password{"status":"true","message":"Login successfully!","data":[{"email":"kowalski@gmail.com","fullname":"Jan Kowalski"}]}
2023-01-06 22:01:27.421 4003-4003/pl.xxxx.xxx V/Toast: show: caller = pl.xxxx.xxx.LoginActivity$3.onResponse:96 
2023-01-06 22:01:27.433 4003-4003/pl.xxxx.xxx I/onSuccess: password{"status":"true","message":"Login successfully!","data":[{"email":"kowalski@gmail.com","fullname":"Jan Kowalski"}]}
2023-01-06 22:01:27.434 4003-4003/pl.xxxx.xxx W/System.err: org.json.JSONException: Value password of type java.lang.String cannot be converted to JSONObject
2023-01-06 22:01:27.435 4003-4003/pl.xxxx.xxx W/System.err:     at org.json.JSON.typeMismatch(JSON.java:112)
2023-01-06 22:01:27.435 4003-4003/pl.xxxx.xxx W/System.err:     at org.json.JSONObject.<init>(JSONObject.java:172)
2023-01-06 22:01:27.435 4003-4003/pl.xxxx.xxx W/System.err:     at org.json.JSONObject.<init>(JSONObject.java:185)
2023-01-06 22:01:27.435 4003-4003/pl.xxxx.xxx W/System.err:     at pl.xxxx.xxx.LoginActivity.parseLoginData(LoginActivity.java:121)
2023-01-06 22:01:27.435 4003-4003/pl.xxxx.xxx W/System.err:     at pl.xxxx.xxx.LoginActivity.access$100(LoginActivity.java:28)
2023-01-06 22:01:27.436 4003-4003/pl.xxxx.xxx W/System.err:     at pl.xxxx.xxx.LoginActivity$3.onResponse(LoginActivity.java:101)
2023-01-06 22:01:27.436 4003-4003/pl.xxxx.xxx W/System.err:     at retrofit2.ExecutorCallAdapterFactory$ExecutorCallbackCall$1$1.run(ExecutorCallAdapterFactory.java:71)
2023-01-06 22:01:27.436 4003-4003/pl.xxxx.xxx W/System.err:     at android.os.Handler.handleCallback(Handler.java:942)
2023-01-06 22:01:27.436 4003-4003/pl.xxxx.xxx W/System.err:     at android.os.Handler.dispatchMessage(Handler.java:99)
2023-01-06 22:01:27.436 4003-4003/pl.xxxx.xxx W/System.err:     at android.os.Looper.loopOnce(Looper.java:226)
2023-01-06 22:01:27.437 4003-4003/pl.xxxx.xxx W/System.err:     at android.os.Looper.loop(Looper.java:313)
2023-01-06 22:01:27.437 4003-4003/pl.xxxx.xxx W/System.err:     at android.app.ActivityThread.main(ActivityThread.java:8741)
2023-01-06 22:01:27.437 4003-4003/pl.xxxx.xxx W/System.err:     at java.lang.reflect.Method.invoke(Native Method)
2023-01-06 22:01:27.437 4003-4003/pl.xxxx.xxx W/System.err:     at com.android.internal.os.RuntimeInit$MethodAndArgsCaller.run(RuntimeInit.java:571)
2023-01-06 22:01:27.437 4003-4003/pl.xxxx.xxx W/System.err:     at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1067)

Nie wiem co to są te błędy w logu powyżej a w szczególności ten:

2023-01-06 22:01:27.434 4003-4003/pl.xxxx.xxx W/System.err: org.json.JSONException: Value password of type java.lang.String cannot be converted to JSONObject

Czy możesz mi podpowiedzieć jak to można zdebugować? - sorry ale jestem jeszcze zielony w Android Studio :(

1
komentarz 6 stycznia 2023 przez bzc0fq Nowicjusz (130 p.)

OK, znalazłem problem... haha ... sam się śmieje z siebie :)

w skrypcie login.php na samym początku było coś takiego:

password<?php

stąd problem z password'ed :)))

głupi błąd, pewnie sobie wkopiowałem przypadkowo...

wszystko już działa...

Dziękuję za pomoc.

komentarz 6 stycznia 2023 przez bzc0fq Nowicjusz (130 p.)

Tak na przyszłość żeby było łatwiej wykryć podobne błędy... czy mógłby ktoś doradzić jak można wyświetlić żądanie POST i wygenerowaną do niego odpowiedź?

Może na poziomie Java/Retorfit w Androidzie bo na poziomie Apache/PHP to jest opisane tutaj.

Wielkie dzięki za pomoc!

komentarz 7 stycznia 2023 przez Wiciorny Ekspert (269,510 p.)
może byś mógł skorzystać z PostMana- dobre narzędzie do tego, albo nie wiem czy umożliwia to twoje IDE
To darmowe narzędzie
https://chrome.google.com/webstore/detail/postman/fhbjgbiflinjbdggehcddcbncdddomop?hl=en
https://beproblemsolver.com/develop-an-api-with-php-json-and-postman/

Podobne pytania

0 głosów
1 odpowiedź 427 wizyt
pytanie zadane 11 czerwca 2022 w Java przez romilus Nowicjusz (120 p.)
0 głosów
0 odpowiedzi 397 wizyt
pytanie zadane 26 maja 2021 w Java przez everstudybee Użytkownik (610 p.)
0 głosów
1 odpowiedź 492 wizyt

92,524 zapytań

141,357 odpowiedzi

319,382 komentarzy

61,914 pasjonatów

Motyw:

Akcja Pajacyk

Pajacyk od wielu lat dożywia dzieci. Pomóż klikając w zielony brzuszek na stronie. Dziękujemy! ♡

Oto polecana książka warta uwagi.
Pełną listę książek znajdziesz tutaj.

Akademia Sekuraka

Kolejna edycja największej imprezy hakerskiej w Polsce, czyli Mega Sekurak Hacking Party odbędzie się już 20 maja 2024r. Z tej okazji mamy dla Was kod: pasjamshp - jeżeli wpiszecie go w koszyku, to wówczas otrzymacie 40% zniżki na bilet w wersji standard!

Więcej informacji na temat imprezy znajdziecie tutaj. Dziękujemy ekipie Sekuraka za taką fajną zniżkę dla wszystkich Pasjonatów!

Akademia Sekuraka

Niedawno wystartował dodruk tej świetnej, rozchwytywanej książki (około 940 stron). Mamy dla Was kod: pasja (wpiszcie go w koszyku), dzięki któremu otrzymujemy 10% zniżki - dziękujemy zaprzyjaźnionej ekipie Sekuraka za taki bonus dla Pasjonatów! Książka to pierwszy tom z serii o ITsec, który łagodnie wprowadzi w świat bezpieczeństwa IT każdą osobę - warto, polecamy!

...