Kotlin安卓:实现okhttp3持续登录,同步到webview

  |   0 评论   |   0 浏览

经常用httpclient请求的的情况下,一般就是用jsoup解析,去爬数据,用okhttp3实现cookie的保存。

这里做的是用okhttp3实现登录请求,然后直接将登录后可访问的页面Cookie同步加载到webview里面去。

将账号与密码保存到shareP ····下次打开webview就可以直接访问已登录页面了。

下面开始具体实现步骤:语言:kotlin,库: okhttp3 组件: webview

先看看一个简单的页面:第一次打开弹出一个账户,填写我们需要的账号与密码

保存到:SharedPreferences。下次登录自动调用login方法,利用okhttp3去请求登录页面。

下面会具体讲。

null

看看代码部分:首先会检查是否添加过账号,添加了就调用登录方法,没有就弹出对话框**(这个对话框不可以返回,触摸关闭哦!)**

val pr = getSharedPreferences("login_flag", Context.MODE_PRIVATE)
login_flag = pr.getString("login_flag","null")
if(login_flag == "null"){//检查是否添加过账户
        Toast.makeText(this@MainActivity,"未添加过账户",Toast.LENGTH_SHORT).show()
        val dialog = AlertDialog.Builder(this@MainActivity)
        val tem_layout = layoutInflater.inflate(R.layout.add,null)
        dialog.setView(tem_layout)//这里用的是对话框的自定义view,导入一个写好的布局
        .setCancelable(false)//设置不可返回,或者触碰空白取消
        .setTitle("添加账户")//用kotlin对象表达实现匿名类,重写监听器。
        .setPositiveButton("确认",object:DialogInterface.OnClickListener{
             override fun onClick(dialog: DialogInterface?, which: Int) {
                 val login_new_name = tem_layout.findViewById<EditText>(R.id.add_name)//这里要获取布局内部控件
                 val login_new_pass = tem_layout.findViewById<EditText>(R.id.add_pass)
                 if(login_new_pass.text.toString()=="" && login_new_pass.text.toString()==""){
            Toast.makeText(this@MainActivity,"不可以为空",Toast.LENGTH_SHORT).show()
        }else{
            val newPr = getSharedPreferences("login_info",Context.MODE_PRIVATE)
            val pr_editor = newPr.edit()
            pr_editor.putString("login_name",login_new_name.text.toString())
            pr_editor.putString("login_pass",login_new_pass.text.toString())
            pr_editor.apply()
            val pr2 = getSharedPreferences("login_flag",Context.MODE_PRIVATE)
            pr2.edit().putString("login_flag","true").apply()
            Toast.makeText(this@MainActivity,"账号:${login_new_name.text.toString()},密码:${login_new_pass.text.toString()}",Toast.LENGTH_SHORT).show()
            }

        }
    })
    .setNegativeButton("取消",null)
    .create()
    .show()
    }else{
        val pr3 = getSharedPreferences("login_info",Context.MODE_PRIVATE)
        val tem_name = pr3.getString("login_name","null")
        val tem_pass = pr3.getString("login_pass","null")
        Toast.makeText(this@MainActivity,"账号:${tem_name},密码:${tem_pass}",Toast.LENGTH_SHORT).show()
        Toast.makeText(this@MainActivity,"正在登录",Toast.LENGTH_SHORT).show()
        login.myLogin(tem_name,tem_pass,myhandle)//调用登录

}

null

下面看看登录类:

 class Login(){
                var cookieStore = HashMap<String, List<Cookie>?>()
                val logUrl = "https://www.login.com"//登录url
                val myManage = "https://www.logined.com"//登录以后可以访问的URL
                val client = OkHttpClient.Builder().cookieJar( object : CookieJar {
                        override fun saveFromResponse(httpUrl: HttpUrl, list: List<Cookie>)
                        {
                        //保存Cookie,主线程要用来同步cookie
                            cookieStore[httpUrl.host()] = list
                        }
                        override fun loadForRequest(httpUrl: HttpUrl): List<Cookie>
                        {
                           val cookies = cookieStore[httpUrl.host()]
                            return cookies ?: ArrayList()
                        }
                }).build() //初始化请求


            fun myLogin(user: String, pw: String, hand: Handler) {
            val isFailLogin = Regex(".*bad.*")//判断是否成功
            val isSuccLogin= Regex(".*ok.*")//判断是否成功
            var res = ""
            if (user.isNotEmpty() && pw.isNotEmpty()) {
            //在主线程中开启一个网络线程

            thread {
            //发送参数
            val myinfo = FormBody.Builder()
            .add("admin_name", user)
            .add("admin_pass", pw)
            .build()
            //构建请求
            var request = Request.Builder().url(this.logUrl).post(myinfo).build()
            var response = this.client.newCall(request).enqueue(object : Callback {//这里用的enqueue有个回调方法,重写可以实现检测请求失败的情况
                override fun onResponse(call: Call, response: Response) {
                    var res = response.body()?.string()//这里string()一定不要使用第二次,比如,如果又用了一次打印xx.string(),就会崩溃!
                        Log.d("here",res)
                        //if(res!!.contains(isSuccLogin)){//自定判断登录,用regex检查或别的。。
                        var msg = Message()
                        msg.what = 1//判断登录,假设1登录ok
                        hand.sendMessage(msg)//发送消息到UI线程
                    }

                override fun onFailure(call: Call, e: IOException) {
                    var msg: Message = Message()
                    msg.what = 4//请求失败
                    hand.sendMessage(msg)
                }
        })
}

//判断提取的信息是否完整
} else {
var msg: Message = Message()
msg.what = 4
hand.sendMessage(msg)
}}}

null

下面回到主线程:

主线程有三个东西:handle webview 还有一个用来同步cookie的方法 syncCookie()先看看handle
//这里用的对象表达式重写
var myhandle = object:Handler(Looper.getMainLooper()){     
   override fun handleMessage(msg: Message) {           
      when(msg.what){      
          1 -> {//登录成功后 
                       synCookie()//调用同步cookie                        
                       Toast.makeText(this@MainActivity,"登录ok",Toast.LENGTH_SHORT).show() 
                       web.loadUrl(login.myManage)//去请求登录后需要的页面                        } 
          2 -> {       
                 }      
      }       
      Log.d("msg",msg.what.toString())     
   }}

看看webview的设置:

val web = findViewById<WebView>(R.id.web)
var web_set = web.settings
web_set.javaScriptEnabled = true//允许JS
web_set.javaScriptCanOpenWindowsAutomatically = true
//重写webClient
//return false 用来阻止超链接会跳到浏览器用的
web.webViewClient = object :WebViewClient(){
    override fun shouldOverrideUrlLoading(view: WebView?, request: WebResourceRequest?): Boolean {
            return false
       }}
web.webChromeClient = WebChromeClient()

下面看看同步方法:AS会提示过时,不用理会


fun synCookie(){
        CookieSyncManager.createInstance(this)
        var cookM = CookieManager.getInstance()
        cookM.setAcceptCookie(true)//允许Cookie
        Log.d("cookie",login.cookieStore.toString())//这里的cookieStore是我们在登录类里定义的一个集合。存储了cookie
        var sessionCookie: Cookie = login.cookieStore["www.xxx.com"]!![0]
        //这是一个装有list的map集合。map键就是url的host部分只要www.xx.com部分,至于值就是0啦。
        //打印看看里面都是啥,name是phpsessionid,value就是值,domain是域名。
        Log.d("sess","name:${sessionCookie.name()};value:${sessionCookie.value()};domain:${sessionCookie.domain()}")
        var cookies = sessionCookie.name() + "=" + sessionCookie.value() + ";domain=" + sessionCookie.domain()
        cookM.setCookie("https://logined.com",cookies)//这个很关键,设置cookie,在指定的url上带上cookie,比如这里是需要登录才可以访问的url
        CookieSyncManager.getInstance().sync()//同步一下
}

null

看一下:

成功的图:自动登录到logined页面了。

null

最后梳理一下:

分两个部分:请求类,主界面的handle

请求类定义了请求url,主界面的handle收到指定信息,实现是否调用同步方法进行webview的cookie同步(其实就是把cookie保留下来,再去调用webview时候,已经有了Cookie买就不用登录了。好了。完了,kotlin的资料太少,参考的都是java的,我不会Java。)


标题:Kotlin安卓:实现okhttp3持续登录,同步到webview
作者:yf_d
地址:看看我的CSDN