今天工作中遇到的一个问题,需求是这样的,需要给dz的论坛做一个android扩展,这肯定少不了会员登录,就得需要二次开发dz提供一个登录接口,眩晕中。。。
因为我对dz不熟悉,所以这个工作对我来说还是有难度的。
仔细分析了一下,在android上为什么需要客户端登录? 答案是肯定的,就是为了获取能唯一标识该用户的信息——uid,其实登录的目的就是这么单纯(提供接口不也是给客户端一个uid嘛)。
那既然只是为了获取一个uid,我们应该还有其他的方式获取,首先就想到了用WEB登录的方式,因为dz已经提供了WAP模块,所以完全可以在应用内以WebView展示一个登录界面让用户登录。
那问题来了, 用户登录后我们怎么获取他的uid呢? 毕竟不是在我们的代码中登录的。。。
反复搜索,终于找到了一个叫:CookieManager的东西,这个类可以获取WebView中的cookie,那我们直接从cookie中获取uid不就ok了?
怀着激动的心情,打开chrome的debug,不断登录...退出...就是为了找到uid的身影,当然结果是令人失望的。
cookie中好像没有是我们想要的东西,找个dz大神问问,原来dz是将加密后的uid写入到cookie中了。。
但是,我们怎么能就这么放弃了呢? 很快我就萌生了一个想法,既然没有uid,我们何不自己把uid写到cookie中呢? 恩,开干! 那我们就需要向dz源码动刀了,首先要找到dz处理登录的文件,才能在处理登录的代码中写入自己的cookie值。再次向dz大神请教,很快,这个文件有了:/source/class/class_member.php,就是这个文件中处理的登录,打开看一下,很长,但是有个方法引起了我的注意:function on_login() , 做android的应该一眼就看出来了,这是登录的“回调”,注意回调我加引号了,但是小细节我们不用关心,最主要的,我们迈出了一大步,继续浏览代码,我发现我还是很幸运的,很快在大约275行的位置,我发现了一段js代码,为什么这段js代码会引起我的注意呢? 你看看就知道了:'setTimeout("window.location.href =\''.$href.'\';", 3000);' 大家都知道,在dz中登录成功会用一个几秒中的等待然后跳转的,找到这段代码太令人兴奋了,那就在这段代码的前后找找,看看有没有位置设置咱们的cookie。
往上看代码,又一个兴奋点来了:if(defined('IN_MOBILE')) 这难道就是区分手机和PC登录的?,二话不说在这里面设置uid的cookie试试:dsetcookie('uid', $_G['uid']); 唉? 怎么和PHP设置cookie的函数不一样? 当你看这个源文件的时候,你会发现很多dsetcookie的代码,这肯定是dz对setcookie的一次封装,咱们直接copy用就ok了,还有一个$_G['uid']也是在这个文件中发现的,我猜测它就是用户的uid了。
赶紧测试一下,好吧。。。在cookie中没有发现uid的身影。。那把设置cookie的这句话网上放放。代码往上走又是一个if语句,这次我直接跳过这个if,直接在if的上面停放了dsetcookie('uid', $_G['uid']); 这句话,继续跟进测试,这次终于在cookie中多了一项,而且,正好,该项是以uid结尾的:
小小激动一下,现在咱们完全可以在cookie中获取uid的值了。
接下来就是android客户端的任务了, 肯定就是一个webview加载dz的登录界面了,这个就不说了,来看看cookie是怎么处理的。
在WebViewClient的onPageFinished方法中:
CookieManager cookieManager = CookieManager.getInstance(); String cookies = cookieManager.getCookie(url); if (null != cookies) { parseUid(cookies); }第一行,我们通过CookieManager的静态方法获取CookieManager实例,紧接着第二行中通过getCookie(String url)方法,获取改url上的cookie,是不是很方便?
在if中调用了一个parseUid的方法,很明显,我们要去取其中的uid了,跟进去看看:
private void parseUid(String cookies) { String[] cookieKeyValues = cookies.split(";"); for(String cookieItem : cookieKeyValues) { if(cookieItem.trim().startsWith("XXX_XXXX_uid")) { String uid = cookieItem.split("=")[1]; System.out.println("uid = " + uid); SharedPreferences.Editor editor = getSharedPreferences( Constants.CONFIG, Context.MODE_PRIVATE).edit(); editor.putBoolean(Constants.IS_LOGIN, true); editor.putInt(Constants.UID, Integer.parseInt(uid)); editor.commit(); finish(); } } }在这个方法中,首先我们用;分割出每一条cookie,因为我发现,多个cookie都是以;分割的,接下来一个遍历,找到以咱们关心的那个cookie的key开头的,然后继续用=分割,因为在字符串中cookie是以key=value的形式存在的。至此,咱们需要的uid就找到了,接下来的几行代码就是写入到本地了,不多说了。
总结:
有时候,一些看似复杂的事情,完全可以用很简单的方式去实现,不过,这需要我们转变一下思路,从另一个思路去思考问题。
当然,上面这种做法肯定有不完美的地方,而且这种方法对于熟悉dz的人来说完全没有必要,但结果还算可以,毕竟给我们省下来很多代码,服务器仅用了一行代码,客户端也区区不到20行的代码就搞定了。