4

Currently, I am still in the proccess of learning Android development so please excuse me if this question of mine is not easily understandable for you.

I create an Android app that is showing a set of list using RecyclerView and when the user click each of the names on the list, it will redirect them to a set of different websites and it will be displayed in WebView. Each of those websites have a different login page. I don't control those websites. Those websites turn off their cookies. Now, is it possible to save user's Username and Password in this situation?

When I included Facebook, Instagram and Twitter, my app able to save the Username and Password (maybe because they are saving cookies?). But if I try the particular websites (with the special situation) that I wanted to add, the Username and Password is not saved.

Since the setSavePassword method is deprecated, I can not found other way to implement saving Username and Password. I have read about SharedPreferences, JavaScript and Autofill several times, but I don't know how to properly implement them into my app. Because from most of what I have read, it is suggested that it will need a login page first to save the Username and Password.

This is my WebView code.

public class WebViewActivity extends AppCompatActivity {

    private WebView webView;
    String url = "";

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.webview);
        
        webView = findViewById(R.id.webView);
        
        WebSettings webSettings = webView.getSettings();
        
        websettings.setDomStorageEnabled(true);
        websettings.setJavaScriptEnabled(true);
        webView.getSettings().setAppCachePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/cache");
        webView.getSettings().setDatabasePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/databases");
        
        if (Build.VERSION.SDK_INT >= 21) {
            CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
        } else {
            CookieManager.getInstance().setAcceptCookie(true);
        }
        
        webView.loadUrl(url);
        
        webView.setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }
        }
        ...
    }
    
    ...
}

Thank you.

Gedanggoreng
  • 186
  • 2
  • 11

2 Answers2

2
public class WebViewActivity extends AppCompatActivity {

    private WebView webView;
    String url = "";

    class MyJavaScriptInterface {
        MyJavaScriptInterface() {
        }
        @SuppressWarnings("unused")
        @JavascriptInterface
        public void processContent(String user,String pass) {
            Log.e("Remember", "user:"+user+" pass:"+pass);
            if (!(user.length() >= 1 && pass.length() >= 1))
                return;

               
            SharedPreferences sharedPreferences = getContext().getSharedPreferences("UserInformation",MODE_PRIVATE);
            if (sharedPreferences.getBoolean("isClickYes", false)) {
                sharedPreferences.edit().putString("us",user).apply();
                sharedPreferences.edit().putString("pass",pass).apply();
            }

            if (!sharedPreferences.getBoolean("isClickYes", false)) {
                AlertDialog alertDialog = new AlertDialog.Builder(getContext())
                        .setTitle("save information")
                        .setMessage("Are You Want Save Password?")

                        .setPositiveButton(android.R.string.yes, new DialogInterface.OnClickListener() {
                            public void onClick(DialogInterface dialog, int which) {
                                sharedPreferences.edit().putString("us",user).apply();
                                sharedPreferences.edit().putString("pass",pass).apply();
                                sharedPreferences.edit().putBoolean("isClickYes",true).apply();
                            }
                        })

                        .setNegativeButton(android.R.string.no, null)
                        .setIcon(android.R.drawable.ic_popup_reminder)
                        .show();
            }

        }
    }

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

        webView = findViewById(R.id.webView);

        WebSettings webSettings = webView.getSettings();

        websettings.setDomStorageEnabled(true);
        websettings.setJavaScriptEnabled(true);
        webView.addJavascriptInterface(new MyJavaScriptInterface(), "INTERFACE");
        webView.getSettings().setAppCachePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/cache");
        webView.getSettings().setDatabasePath(getApplicationContext().getFilesDir().getAbsolutePath() + "/databases");

        if (Build.VERSION.SDK_INT >= 21) {
            CookieManager.getInstance().setAcceptThirdPartyCookies(webView, true);
        } else {
            CookieManager.getInstance().setAcceptCookie(true);
        }

        webView.setWebViewClient(new WebViewClient(){
            @Override
            public void onPageFinished(WebView view, String url) {
                super.onPageFinished(view, url);
            }



private void runOnUi(int page, WebView view ,SharedPreferences sharedPreferences) {
    int LOGIN      = 0;
    int LOGIN_PASS = 1;
    WebViewActivity.this.runOnUiThread(() -> {
        if (page == LOGIN_PASS) {
        view.loadUrl("javascript:(function(){l=document.getElementById(\"formLogin\"); l.setAttribute(\"onclick\",\"" +
                "INTERFACE.processContent(  document.getElementById('txtUserId').value , document.getElementById('txtPassword').value  );\"   );       " + "})()");

        if (sharedPreferences.getBoolean("isClickYes", false)) {
            String pass = sharedPreferences.getString("pass", "");
            view.loadUrl("javascript:(function(){l=document.getElementById('txtPassword');l.value='" + pass + "'; })()");
        }
        } else if (page == LOGIN) {
            String user = sharedPreferences.getString("us", "");
            view.loadUrl("javascript:(function(){l=document.getElementById('txtUserId2');l.value='" + user + "'; })()");
        }
    });
}



            @Nullable
            @Override
            public WebResourceResponse shouldInterceptRequest(WebView view, WebResourceRequest request) {




    if (request.getUrl().toString().equals("https/.../....png")) {
        SharedPreferences sharedPreferences = getContext().getSharedPreferences("UserInformation", MODE_PRIVATE);
        if (request.getRequestHeaders().toString().contains("Referer=https/...../loginpass"))
            runOnUi(1, view, sharedPreferences);
        else if (request.getRequestHeaders().toString().contains("Referer=https/...../login"))
            runOnUi(0, view, sharedPreferences);
    }



                return super.shouldInterceptRequest(view, request);
            }
        }
    
    }
    
    webView.loadUrl(url);
    ...
}
Zoe
  • 27,060
  • 21
  • 118
  • 148
nima
  • 432
  • 5
  • 6
  • I did not write yourLoginUrl and urlContains because you said it had a security reason. If you were online, I would go to their address – nima Sep 13 '21 at 06:11
  • Can I put (url + "/login") to replace (""yourLoginUrl") ? – Gedanggoreng Sep 13 '21 at 11:33
  • Instead of shouldInterceptRequest, you could put these codes in onFinish. But onFinish sometimes ends late and I think this method was better. – nima Sep 13 '21 at 11:54
  • After clicking on the submit, the user and password are sent to the processContent method.You can see it in the log – nima Sep 13 '21 at 11:57
  • I have tried it several times., but it didn't work. Is it possible that the yourLoginUrl & urlContains I inputted is wrong? – Gedanggoreng Sep 13 '21 at 14:30
  • Did you start yourLoginUrl with https? ->"https:// Link.png" – nima Sep 13 '21 at 14:57
  • I tried this code and there is no problem – nima Sep 13 '21 at 15:05
  • Note that this code only sends the password and username to the Java method. If you want to enter it in the user box when you log in, you must first save this password in the database or in the ShPreferences . And when the user enters the login page, enter it in JavaScript in the box. – nima Sep 13 '21 at 15:11
  • Please can you kindly add the sharedpreferences codes in your answer above? – Gedanggoreng Sep 13 '21 at 17:05
  • There is no problem, I will do it. But if you learn yourself, you can expand your program much better. For example, you can show a dialog to the user that you want to save the password. Or do not show the dialog again and enter automatically and ... I did not know any of this and I learned it over and over again – nima Sep 13 '21 at 17:25
  • Do you want the dialog to be shown to the user? – nima Sep 13 '21 at 17:25
  • Yes, please. It's better to show an option to users if they want to save the username and password or not. – Gedanggoreng Sep 13 '21 at 17:29
  • Edited..!You can customize it yourself and add more features to it. – nima Sep 13 '21 at 19:51
  • Would you mind informing your email address so I can contact you personally? – Gedanggoreng Sep 13 '21 at 21:04
  • nimabandari27@gmail.com – nima Sep 14 '21 at 03:11
  • Sorry for delayed respond. I have just tried your code. And yes, it surely does work nicely. I don't know how you pull the trick, but it works. Thanks, Nima. – Gedanggoreng Sep 16 '21 at 20:01
  • Where can I find the file containing my saved password? Is it saved in my phone's storage? – Gedanggoreng Sep 16 '21 at 20:34
  • you're welcome.Shperfrences creates an xml file in the data/data/yourpackname /shared_prefs directory.To access this part of your phone, you must be rooted. Or you can see the file with Android emulator.The .getSharedPreferences command ("UserInformation", MODE_PRIVATE) checks if there is a file named UserInformation in this section and returns it, and if it does not have one, it builds and returns it. Command putString or ... You can add a value in this file. And with the command getString and ... you can enter the value you have already set – nima Sep 17 '21 at 05:07
  • i edit code.i change shluldInerceptRequest and add runOnUi method in above code!Now the user is also saved – nima Sep 17 '21 at 06:23
  • Note that the work of the shluldInerceptRequest method is something else. When the url wants to be loaded, when calling any of the urls (such as images, scripts, etc.) this method is called. The reason I use .png is that this file is loaded at the end and after loading HTML.And the password field is loaded so I can get the value . And I used this method instead onFinish method because I don't think that onFinish is accurate! – nima Sep 17 '21 at 06:33
  • Thanks for the updated code, Nima. I noticed that the pop up dialog will only shown once, and it will save Username and Password of other websites too, if I put them in yourLoginUrl and urlContains. I wonder is it possible for the pop up dialog to show per website? So if I choose not to save Username and Password for one website, it will not affect the pop up to show for other websites? I use the WebView from RecyclerView. – Gedanggoreng Sep 17 '21 at 07:42
  • Yes document.getElementById ('txtPassword') is for this site and for other sites you have to put txtPassword on that site and ... for each site shperfrenes should be saved with the address of that site. I am trying to see if there is a way has it – nima Sep 17 '21 at 07:59
  • Yes, Nima. It's fine for me to input every site's yourLoginUrl and urlContains. But I need the pop up dialog to show for every each of those websites, so user have the freedom to save per website. – Gedanggoreng Sep 17 '21 at 08:06
  • Okay .I'm trying – nima Sep 17 '21 at 08:08
  • And thanks for explaining the reason behind using png for yourLoginUrl. I have been wondering why I need to use the png ever since you shared the code. – Gedanggoreng Sep 17 '21 at 08:08
  • And what about "referer = ..." in urlContains? Why we should use it? – Gedanggoreng Sep 17 '21 at 08:10
  • you're welcome . Sorry if my English is bad. – nima Sep 17 '21 at 08:13
  • Relax, Nima. You are doing fine with your English. – Gedanggoreng Sep 17 '21 at 08:21
  • The site that loads on your phone sends Get and Post requests. You can see these requests in shluldInerceptRequest. Also block them and even inject your own script or png or ... request.getUrl ( ) Get the address of the response from the site. For example, https: /.../ example.json takes a Json file and uploads it to this webview. You can give it another address and inject Json yourself. The accompanying request header sends headers that you can view at request.getRequestHeaders ().With request.getMethod () you can also see it is sent by GET or POST.log these and you can see everything sent – nima Sep 17 '21 at 08:28
  • The png address was all the pages of this site. And I used the "referer = ..." to run this code only on the login page (that is, I found something that is unique to this page). Others should check to find an address that is unique to that page – nima Sep 17 '21 at 08:34
  • I just sent you an email asking for something – Gedanggoreng Nov 11 '21 at 15:52
  • i tried to save http://175.107.63.74/sm3p/login information but failed. any solution – Attaullah Nov 18 '22 at 09:16
  • @Attaullah Do you still need help on this? – Gedanggoreng Jan 30 '23 at 12:53
0

Instead of such a 1000 lines of code write this

webview.getSettings().setSavePassword(true);

webview.loadUrl("url");
  • 3
    This method was deprecated in API level 18. Source : https://developer.android.com/reference/android/webkit/WebSettings#setSavePassword(boolean) – Gedanggoreng Mar 27 '22 at 17:31