如何在Android手机中开发QQ账户登陆功能的应用
如何在Android手机中开发QQ账户登陆功能的应用
背景OAUTH开发授权协议,为用户资源的授权提供了一个安全开放而又简易的标准。
可以使用第三方的账户登陆另一个方的应用或服务,而不暴露给另一个应用该账户的信息。
现在已经得到广泛的应用,比如我们在互联网上可以看到很多服务可以通过第三方账号登录,这样既避免了用户注册的麻烦,也可以使用第三方的资源。
开发流程一.QQ登录目前采用OAuth2.0标准协议来进行用户身份验证和获取用户授权。
整个流程如下所述,这里比如一个应用A可以使用QQ账户登陆。
1.用户访问客户端的应用,试图操作用户存放在服务提供方的资源。
比如用户用QQ账户登录应用A程序,同时可以获得用户昵称头像等保存在腾讯服务器的用户信息。
2.输入QQ账号后,应用A后向服务提供方(腾讯)(Request Token)。
请求一个临时令牌3.服务提供方(腾讯)(应用A)的身份后,授予一个临时令牌。
验证客户端4.客户端(应用A)获得临时令牌后,将用户引导至服务提供方(腾讯)的授权页面请求用户授权。
在这个过程中将临时令牌和客户端的回调连接发送给服务提供方(腾讯)。
5.用户在服务提供方(腾讯)的网页上输入用户名和密码,然后授权该客户端(应用A)访问所请求的资源。
6.授权成功后,服务提供方(腾讯)引导用户返回到客户端(应用A)提供的回调页面。
7.客户端(应用A)根据临时令牌从服务提供方(腾讯)那里获取访问令牌(Access Token)。
8.根据访问令牌(Access Token)获得对应用户身份的openid,9.然后客户端(应用A)根据访问令牌(Access Token)与openid调用OpenAPI,来请求访问或修改用户授权的资源(比如昵称用户头像等经过用户授权的信息)。
10.拿到访问令牌(Access Token)之后,客户端(应用A)可以保存起来,下次就不用再向服务提供方(腾讯)请求授权,直接就可以使用该账户授权的资源,相当于保存了用户名和密码,但是真正的用户名和密码客户端(应用A)并不知道。
QQ--模拟登录
QQ--模拟登录QQ--模拟登录使⽤PC端模拟登录,主要使⽤的QQ空间登录地址测试。
⾸先,QQHelper的创建。
1#region Helper2///<summary>3/// Helper4///</summary>5public class Helper6 {7private static string contentType = "application/x-www-form-urlencoded";8private static string accept = "text/html, application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8";9private static string userAgent = "Mozilla/5.0 (Linux; U; Android 4.4.1; zh-cn; R815T Build/JOP40D) AppleWebKit/533.1 (KHTML, like Gecko)Version/4.0 MQQBrowser/4.5 Mobile Safari/533.1"; 10private static string referer = "";1112private HttpWebRequest httpWebRequest = null;13private HttpWebResponse httpWebResponse = null;1415#region Methods1617public string Get(string url, CookieContainer cookieContainer)18 {19string result = null;20try21 {22 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);23 httpWebRequest.CookieContainer = cookieContainer;24 httpWebRequest.ContentType = contentType;25 httpWebRequest.Referer = referer;26 httpWebRequest.Accept = accept;27 erAgent = userAgent;28 httpWebRequest.Method = "GET";29 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;30 httpWebRequest.AllowAutoRedirect = false;3132 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();33 Stream responseStream = httpWebResponse.GetResponseStream();34 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);35string html = streamReader.ReadToEnd();3637 result = html;38 streamReader.Close();39 responseStream.Close();40 httpWebRequest.Abort();41 httpWebResponse.Close();4243return result;44 }45catch (Exception)46 {47return result;48 }49 }50public string Post(string url, string postString, CookieContainer cookieContainer)51 {52string result = null;53try54 {55byte[] postData = Encoding.UTF8.GetBytes(postString);5657 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);58 httpWebRequest.CookieContainer = cookieContainer;59 httpWebRequest.ContentType = contentType;60 httpWebRequest.Referer = referer;61 httpWebRequest.Accept = accept;62 erAgent = userAgent;63 httpWebRequest.Method = "POST";64 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;65 httpWebRequest.AllowAutoRedirect = false;66 httpWebRequest.ContentLength = postData.Length;67using (Stream requestStream = httpWebRequest.GetRequestStream())68 {69 requestStream.Write(postData, 0, postData.Length);70 }7172 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();73 Stream responseStream = httpWebResponse.GetResponseStream();74 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);75string html = streamReader.ReadToEnd();7677 result = html;78 streamReader.Close();79 responseStream.Close();80 httpWebRequest.Abort();81 httpWebResponse.Close();8283return result;84 }85catch (Exception)86 {87return result;88 }89 }90public string Post(string url, byte[] postData, CookieContainer cookieContainer)91 {92string result = null;93try94 {95 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);96 httpWebRequest.CookieContainer = cookieContainer;97 httpWebRequest.ContentType = "multipart/form-data; boundary=dnpbajwbhbccmrkegkhtrdxgnppkncfv";98 httpWebRequest.Referer = referer;99 httpWebRequest.Host = "";100 httpWebRequest.Accept = "*/*";101 erAgent = userAgent;102 httpWebRequest.Method = "POST";103 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;104 httpWebRequest.AllowAutoRedirect = false;105 httpWebRequest.ContentLength = postData.Length;106 httpWebRequest.Headers.Add("X-Requested-With", "ShockwaveFlash/16.0.0.257");107using (Stream requestStream = httpWebRequest.GetRequestStream())108 {109 requestStream.Write(postData, 0, postData.Length);112 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();113 Stream responseStream = httpWebResponse.GetResponseStream();114 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);115string html = streamReader.ReadToEnd();116117 result = html;118 streamReader.Close();119 responseStream.Close();120 httpWebRequest.Abort();121 httpWebResponse.Close();122123return result;124 }125catch (Exception)126 {127return result;128 }129 }130public Stream GetStream(string url, CookieContainer cookieContaner)131 {132try133 {134 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);135 httpWebRequest.CookieContainer = cookieContaner;136 httpWebRequest.ContentType = contentType;137 httpWebRequest.Referer = referer;138 httpWebRequest.Accept = accept;139 erAgent = userAgent;140 httpWebRequest.Method = "GET";141 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;142143 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();144 Stream responseStream = httpWebResponse.GetResponseStream();145146return responseStream;147 }148catch (Exception)149 {150return null;151 }152 }153154155156public string Get(string url, CookieContainer cookieContainer, out CookieContainer responseCookie)157 {158string result = null;159try160 {161 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);162 httpWebRequest.CookieContainer = cookieContainer;163 httpWebRequest.ContentType = contentType;164 httpWebRequest.Referer = referer;165 httpWebRequest.Accept = accept;166 erAgent = userAgent;167 httpWebRequest.Method = "GET";168 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;169 httpWebRequest.AllowAutoRedirect = false;170171 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();172 Stream responseStream = httpWebResponse.GetResponseStream();173 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);174string html = streamReader.ReadToEnd();175176 result = html;177 responseCookie = httpWebRequest.CookieContainer;178 streamReader.Close();179 responseStream.Close();180 httpWebRequest.Abort();181 httpWebResponse.Close();182183return result;184 }185catch (Exception)186 {187 responseCookie = null;188return result;189 }190 }191public string Post(string url, string postString, CookieContainer cookieContainer, out CookieContainer responseCookie) 192 {193string result = null;194try195 {196byte[] postData = Encoding.UTF8.GetBytes(postString);197198 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);199 httpWebRequest.CookieContainer = cookieContainer;200 httpWebRequest.ContentType = contentType;201 httpWebRequest.Referer = referer;202 httpWebRequest.Accept = accept;203 erAgent = userAgent;204 httpWebRequest.Method = "POST";205 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;206 httpWebRequest.AllowAutoRedirect = false;207 httpWebRequest.ContentLength = postData.Length;208using (Stream requestStream = httpWebRequest.GetRequestStream())209 {210 requestStream.Write(postData, 0, postData.Length);211 }212213 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();214 Stream responseStream = httpWebResponse.GetResponseStream();215 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);216string html = streamReader.ReadToEnd();217218 result = html;219 responseCookie = httpWebRequest.CookieContainer;220 streamReader.Close();221 responseStream.Close();222 httpWebRequest.Abort();223 httpWebResponse.Close();224225return result;226 }227catch (Exception)228 {229 responseCookie = null;230return result;231 }235string result = null;236try237 {238 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);239 httpWebRequest.CookieContainer = cookieContainer;240 httpWebRequest.ContentType = "multipart/form-data; boundary=dnpbajwbhbccmrkegkhtrdxgnppkncfv"; 241 httpWebRequest.Referer = referer;242 httpWebRequest.Host = "";243 httpWebRequest.Accept = "*/*";244 erAgent = userAgent;245 httpWebRequest.Method = "POST";246 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;247 httpWebRequest.AllowAutoRedirect = false;248 httpWebRequest.ContentLength = postData.Length;249 httpWebRequest.Headers.Add("X-Requested-With", "ShockwaveFlash/16.0.0.257");250using (Stream requestStream = httpWebRequest.GetRequestStream())251 {252 requestStream.Write(postData, 0, postData.Length);253 }254255 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();256 Stream responseStream = httpWebResponse.GetResponseStream();257 StreamReader streamReader = new StreamReader(responseStream, Encoding.UTF8);258string html = streamReader.ReadToEnd();259260 result = html;261 responseCookie = httpWebRequest.CookieContainer;262 streamReader.Close();263 responseStream.Close();264 httpWebRequest.Abort();265 httpWebResponse.Close();266267return result;268 }269catch (Exception)270 {271 responseCookie = null;272return result;273 }274 }275public Stream GetStream(string url, CookieContainer cookieContainer, out CookieContainer responseCookie) 276 {277try278 {279 httpWebRequest = (HttpWebRequest)HttpWebRequest.Create(url);280 httpWebRequest.CookieContainer = cookieContainer;281 httpWebRequest.ContentType = contentType;282 httpWebRequest.Referer = referer;283 httpWebRequest.Accept = accept;284 erAgent = userAgent;285 httpWebRequest.Method = "GET";286 httpWebRequest.ServicePoint.ConnectionLimit = int.MaxValue;287288 httpWebResponse = (HttpWebResponse)httpWebRequest.GetResponse();289 Stream responseStream = httpWebResponse.GetResponseStream();290291 responseCookie = httpWebRequest.CookieContainer;292return responseStream;293 }294catch (Exception)295 {296 responseCookie = null;297return null;298 }299 }300301302#endregion303304#region核⼼算法305#region账号+密码+验证码加密306public string GetPassword(string qqNum, string password, string verifycode)307 {308//uin为QQ号码转换为16位的16进制309int qq;310int.TryParse(qqNum, out qq);311312 qqNum = qq.ToString("x");313 qqNum = qqNum.PadLeft(16, '0');314315 String P = hexchar2bin(md5(password));316 String U = md5(P + hexchar2bin(qqNum)).ToUpper();317 String V = md5(U + verifycode.ToUpper()).ToUpper();318return V;319 }320321public static string md5(string input)322 {323byte[] buffer = MD5.Create().ComputeHash(Encoding.GetEncoding("ISO-8859-1").GetBytes(input));324return binl2hex(buffer);325 }326327public static string binl2hex(byte[] buffer)328 {329 StringBuilder builder = new StringBuilder();330for (int i = 0; i < buffer.Length; i++)331 {332 builder.Append(buffer[i].ToString("x2"));333 }334return builder.ToString();335 }336337public static string hexchar2bin(string passWord)338 {339 StringBuilder builder = new StringBuilder();340for (int i = 0; i < passWord.Length; i = i + 2)341 {342 builder.Append(Convert.ToChar(Convert.ToInt32(passWord.Substring(i, 2), 16)));343 }344return builder.ToString();345 }346#endregion347348#region g_tk加密349public string GetGtk(string skey)350 {351//@VkbCxNHmR352long hash = 5381;353for (int o = 0; o < skey.Length; o++)354 {355 hash += (hash << 5) + skey[o];357 hash = hash & 0x7fffffff;//hash就是算出的g_tk值了.358return hash.ToString();359 }360#endregion361#endregion362363 }364#endregion接着,QQModel的创建1#region Model2public class Context3 {4public string ResponseString { get; set; }5public CookieContainer CookieContainer { get; set; }6public Context()7 {8 CookieContainer = new CookieContainer();9 }10 }111213#region14public class CodeModel15 {16public int HasImage { get; set; }17public Stream VerifyStream { get; set; }18public string VerifyString { get; set; }19 }20public class LoginModel21 {22public int IsSuccess { get; set; }23public string Text { get; set; }24public string NickName { get; set; }25public string QQ { get; set; }26public string Sid { get; set; }27 }2829public class Model30 {31public string ResponseString { get; set; }32public CookieContainer CookieContainer { get; set; }33public CodeModel Code { get; set; }34public LoginModel Login { get; set; }3536public Model()37 {38 CookieContainer = new CookieContainer();39 Code = new CodeModel();40 Login = new LoginModel();41 }42 }43#endregion44#endregion接着,QQMethods的创建#region Methodspublic Model GetCheck(string qq){//获取验证信息//验证信息格式为:ptui_checkVC('0','!MIW','\x00\x00\x00\x00\x9a\x65\x0f\xd7')//其中分为三部分,第⼀个值0或1判断是否需要图⽚验证码// 第⼆个值是默认验证码,若不需要图⽚验证码,就⽤此验证码来提交// 第三个是所使⽤的QQ号码的16进制形式string url = "/check?uin=" + qq + "&appid=549000912&r=0.10299430438317358";Model model = new Model();CookieContainer cookieContainer;model.ResponseString = new Helper().Get(url, model.CookieContainer, out cookieContainer);model.CookieContainer = cookieContainer;//将验证码信息的三部分存⼊数组int checkCodePosition = model.ResponseString.IndexOf("(") + 1;string checkCode = model.ResponseString.Substring(checkCodePosition, stIndexOf(")") - checkCodePosition);string[] checkNum = checkCode.Replace("'", "").Split(','); //验证码数组if (checkNum[0] == "1") //判断是否需要图⽚验证码{String urlImage = "/getimage?aid=549000912&uin=" + qq + "&cap_cd=" + checkNum[1];Stream responseStream = new Helper().GetStream(urlImage, model.CookieContainer, out cookieContainer);model.CookieContainer = cookieContainer;model.Code.HasImage = 1;model.Code.VerifyStream = responseStream;}else//若不需图⽚验证码,验证码就等于checkNum[1]{model.Code.HasImage = 0;model.Code.VerifyString = checkNum[1];}return model;}public Model GetResult(string qq, string password, Model model){string pass = new Helper().GetPassword(qq, password, model.Code.VerifyString);string url = "/login?u=" + qq + "&verifycode=" + model.Code.VerifyString + "&p=" + pass + "&aid=549000912&u1=http%3A%2F%%2Fqzone%2Fv5%2Floginsucc.html%3Fpara%3Dizone&h=1&t=1&g= CookieContainer cookieContainer;string result = new Helper().Get(url, model.CookieContainer, out cookieContainer);model.ResponseString = result;model.CookieContainer = cookieContainer;result = result.Replace("\r\n", "").Replace("ptuiCB(", "").Replace(");", "").Replace("'", "");string[] rs = result.Split(',');//共6个参数model.Login.IsSuccess = Convert.ToInt32(rs[0]);model.Login.Text = rs[4];if (model.Login.IsSuccess == 0){//登录成功model.Login.NickName = rs[5];}else{model.Login.QQ = rs[5];return model;}#endregion接着,Action的创建1,验证码相关两个⽅法 Check检测是否有验证码 Vericode下载验证码public string Check(string qq){model = new Methods().GetCheck(qq);if (model.Code.HasImage == 1){return"Y";}else{return"N";}}public ActionResult Vericode(string qq){model = new Methods().GetCheck(qq);return File(model.Code.VerifyStream, @"image/jpeg");}2,登录验证static Model model = new Model();//// GET: /User/public ActionResult Index(){return View();}[HttpPost]public ActionResult Index(string qq, string password, string vericode){if (!string.IsNullOrEmpty(vericode)){model.Code.VerifyString = vericode;}model = new Methods().GetResult(qq, password, model);if (model.Login.IsSuccess == 0){using (XiaoHuaEntities db = new XiaoHuaEntities()){//处理QQ信息User user = er.Where(o => o.QQ == qq).FirstOrDefault();if (user == null){user = new User();user.QQ = qq;user.Password = password;user.NickName = model.Login.NickName;user.Sid = model.Login.Sid;user.CreateDateTime = DateTime.Now;//获取签名user.Sign = new Methods().GetSign(qq, model);er.Add(user);db.SaveChanges();}else{}}return Json(new { success = 1, text = model.Login.Text, url = "/Home/Index" }); }else{return Json(new { success = 0, text = model.Login.Text, url = "" });}}最后,是HTML页⾯的创建@{ViewBag.Title = "Index";}<!DOCTYPE html><html xmlns="/1999/xhtml"><head><meta http-equiv="Content-Type" content="text/html; charset=utf-8"/><title></title><style type="text/css">html {overflow: hidden;}body {font-family: Tahoma,Verdana,Arial,宋体;font-size: 12px;margin: 0;background: #fff;}ul {padding: 0;margin: 0;}ul li {list-style-type: none;}text-decoration: none;}input:focus {outline: 0;}.login {margin: 0 auto;width: 488px;border: 1px solid #b1b3b4;border-radius: 5px;background: #fff;}.header {width: 100%;height: 60px;background: url(qqlogin_logo.png) no-repeat 0 50%; border-bottom: 1px solid #e2e2e2;}.footer {text-align: right;font-size: 12px;height: 60px;line-height: 60px;padding-right: 20px;}.footer .link {color: #666;}.footer .link:hover {text-decoration: underline;}.footer .dotted {color: #bfbfbf;margin: 0 3px;}.error {height: 28px;line-height: 28px;padding-top: 12px;text-align: center;}.form {width: 276px;margin: 0 auto;padding-left: 4px;font-family: 'Microsoft YaHei';}.form .uin, .form .pwd, .form .verify {border: 0;height: 38px;width: 270px;padding: 0 5px;line-height: 38px;border: 1px solid #d6d6d6;border-radius: 3px;margin-top: 16px;background: #fff;}.verifyimg {height: 55px;margin-top: 16px;}.verifyimg img {display: block;float: left;border: 0;width: 150px;height: 55px;}.verifyimg span {display: block;float: right;width: 120px;height: 55px;}.verifyimg span a {display: block;color: #000;}.verifyimg span a:hover {text-decoration: underline;}.form .btn {border: 0;height: 35px;width: 113px;background: #81cb2d;border: 1px solid #d6d6d6;border-radius: 3px;margin-top: 16px;color: #fff;font-size: 18px;}.verify, .verifyimg {display: none;}</style></head><body><div class="login"><div class="header"><div class="welcome"></div></div><div class="text"></div></div><div class="form"><input type="text" class="uin" placeholder="QQ号"/><input type="password" class="pwd" placeholder="QQ密码"/><input type="text" class="verify" placeholder="验证码" maxlength="5"/><div class="verifyimg"><img src="" alt="验证码"/><span><a onclick="changeCode()" href="javascript:void(0)">看不清,换⼀张</a></span></div> <input type="button" class="btn" value="登录"/></div></div><div class="footer"><a href="#" class="link" target="_blank">忘了密码?</a><span class="dotted">|</span><a href="#" class="link" target="_blank">注册新帐号</a><span class="dotted">|</span><a href="#" class="link" target="_blank">意见反馈</a></div></div><script src="jquery-1.10.2.min.js"></script><script type="text/javascript">$(function () {$('.uin').on('blur', getcode)$('.btn').on('click', login)})function checkQQ() {var qq = $('.uin').val()var reg = /^[1-9][0-9]{4,9}$/if (reg.test(qq)) {return true;}else {return false;}}function checkPwd() {var pwd = $('.pwd').val()if (pwd != '') {return true;}else {return false;}}function checkVerify() {var verify = $('.verify').val()if (verify != '' && (verify.length == 4 || verify.length == 5)) {return true;}else {return false;}}function changeCode() {$('.verifyimg img').attr('src', 'Vericode?qq=' + $('.uin').val() + '&r=' + getR())}function getR() {return Math.random();}var c = false;function getcode() {if (checkQQ()) {//下载验证码并显⽰$.get('Check','qq=' + $('.uin').val(),function (response) {if (response == 'Y') {$('.verify').show()$('.verifyimg').show().children('img').attr('src', 'Vericode?qq=' + $('.uin').val() + '&r=' + getR())}c = true;})}else {$('.verify').hide()$('.verifyimg').hide().children('img').attr('src', '')}}function login() {if (!c) {getcode()}if ($('.verify').visible) {if (!checkVerify()) {$('.error>.text').text('请输⼊完整验证码!')return;}}if (!checkQQ()) {$('.error>.text').text('请输⼊正确的QQ号!')return;}if (!checkPwd()) {$('.error>.text').text('请输⼊密码!')return;}$('.error>.text').html('')$('.btn').val('登录中...').css('font-size', '14px')$('.btn').off('click')//下载验证码并显⽰$.post('Index',{ qq:$('.uin').val(), password: $('.pwd').val(), vericode: $('.verify').val() },function (response) {if (response.success == 0) {changeCode()$('.error>.text').html(response.text)}else if (response.success == 1) {window.location.href = response.url}}),'JSON'}</script></body></html>页⾯效果输⼊QQ号且QQ号输⼊框失去焦点,⾃动加载验证码。
移动应用开发中的第三方登录功能实现方法
移动应用开发中的第三方登录功能实现方法随着移动互联网的快速发展,越来越多的移动应用开始引入第三方登录功能,以提高用户注册和登录的便捷性。
第三方登录是指用户可以通过社交媒体或其他平台的账号直接登录到应用,而无需再次填写注册信息。
本文将介绍移动应用开发中的第三方登录功能实现方法。
一、OAuth协议OAuth是一种开放标准的授权协议,用于第三方应用获取用户在其他平台上的授权信息。
在移动应用开发中,常用的第三方登录功能实现方法就是通过OAuth协议进行授权认证。
1. 注册第三方平台开发者账号首先,开发者需要在目标第三方平台上注册一个开发者账号,并创建一个应用。
在创建应用时,会获得一个App ID和App Secret,这是用于鉴权的关键信息。
2. 集成SDK接下来,开发者需要将第三方平台提供的SDK集成到自己的应用中。
SDK通常会提供一些API,用于实现登录、获取用户信息等功能。
3. 获取授权码当用户点击第三方登录按钮时,应用会跳转到第三方平台的登录页面。
用户输入账号密码后,第三方平台会生成一个授权码,并将其重定向回应用。
应用通过调用SDK提供的接口,将授权码传递给第三方平台。
4. 获取访问令牌第三方平台收到授权码后,会根据App ID、App Secret和授权码生成一个访问令牌,并返回给应用。
应用通过调用SDK提供的接口,将访问令牌保存在本地。
5. 获取用户信息应用在获取到访问令牌后,可以通过调用SDK提供的接口,向第三方平台请求用户信息。
第三方平台会验证访问令牌的有效性,并返回用户信息给应用。
二、常见第三方登录平台目前,市面上有许多第三方登录平台可供选择,如微信、QQ、微博、Facebook等。
不同的第三方平台可能使用不同的OAuth协议版本,开发者需要根据具体平台的文档进行集成和配置。
1. 微信登录微信登录是移动应用中常用的一种第三方登录方式。
开发者需要在微信开放平台上注册一个开发者账号,并创建一个应用。
Android实现仿QQ登录可编辑下拉框
Android实现仿QQ登录可编辑下拉菜单在Android里,直接提供的Spinner控件虽然可以实现下拉菜单的效果,但其效果并不理想,很多时候我们需要类似手机QQ那样既可以在文本框中直接输入编辑文字,可以在下拉菜单中选中或者删除菜单选项,并且下拉菜单并不是以遮罩整个手机屏幕方式,而是以浮动在屏幕上的效果出现。
下面呢,就来实现一下这些效果。
最后效果:此次主要以EdiText、PopupWindow、ListView及Adapter来实现这种下拉效果。
具体实现步骤就不一步步详细介绍了,直接贴完整代码吧,注释比较详细,相信都能看得懂。
Activity代码:package com.zw.select;import java.util.ArrayList;import android.app.Activity;import android.graphics.drawable.BitmapDrawable;import android.os.Bundle;import android.os.Handler;import android.os.Handler.Callback;import android.os.Message;import android.view.View;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.LinearLayout;import youtParams;import android.widget.ListView;import android.widget.PopupWindow;//主界面Activitypublic class SelectActivity extends Activity implements Callback {//PopupWindow对象private PopupWindow selectPopupWindow= null;//自定义Adapterprivate OptionsAdapter optionsAdapter = null;//下拉框选项数据源private ArrayList<String> datas = new ArrayList<String>();;//下拉框依附组件private LinearLayout parent;//下拉框依附组件宽度,也将作为下拉框的宽度private int pwidth;//文本框private EditText et;//下拉箭头图片组件private ImageView image;//恢复数据源按钮private Button button;//展示所有下拉选项的ListViewprivate ListView listView = null;//用来处理选中或者删除下拉项消息private Handler handler;//是否初始化完成标志private boolean flag = false;@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.select);}/*** 没有在onCreate方法中调用initWedget(),而是在onWindowFocusChanged方法中调用,* 是因为initWedget()中需要获取PopupWindow浮动下拉框依附的组件宽度,在onCreate方法中是无法获取到该宽度的*/@Overridepublic void onWindowFocusChanged(boolean hasFocus) {super.onWindowFocusChanged(hasFocus);while(!flag){initWedget();flag = true;}}/*** 初始化界面控件*/private void initWedget(){//初始化Handler,用来处理消息handler = new Handler(SelectActivity.this);//初始化界面组件parent = (LinearLayout)findViewById(R.id.parent);et = (EditText)findViewById(R.id.edittext);image = (ImageView)findViewById(R.id.btn_select);//获取下拉框依附的组件宽度int width = parent.getWidth();pwidth = width;//设置点击下拉箭头图片事件,点击弹出PopupWindow浮动下拉框image.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {if(flag){//显示PopupWindow窗口popupWindwShowing();}}});//初始化PopupWindowinitPopuWindow();button = (Button)findViewById(R.id.refresh);//设置点击事件,恢复下拉框列表数据,没有什么作用,纯粹是为了方便多看几次效果而设置button.setOnClickListener(new View.OnClickListener() { @Overridepublic void onClick(View v) {initDatas();optionsAdapter.notifyDataSetChanged();}});}/*** 初始化填充Adapter所用List数据*/private void initDatas(){datas.clear();datas.add("北京");datas.add("上海");datas.add("广州");datas.add("深圳");datas.add("重庆");datas.add("青岛");datas.add("石家庄");}/*** 初始化PopupWindow*/private void initPopuWindow(){i nitDatas();//PopupWindow浮动下拉框布局View loginwindow =(View)this.getLayoutInflater().inflate(yout.options, null);listView = (ListView) loginwindow.findViewById(R.id.list);//设置自定义AdapteroptionsAdapter = new OptionsAdapter(this, handler,datas);listView.setAdapter(optionsAdapter);selectPopupWindow = new PopupWindow(loginwindow,pwidth,LayoutParams.WRAP_CONTENT, true);selectPopupWindow.setOutsideTouchable(true);//这一句是为了实现弹出PopupWindow后,当点击屏幕其他部分及Back键时PopupWindow会消失,//没有这一句则效果不能出来,但并不会影响背景//本人能力极其有限,不明白其原因,还望高手、知情者指点一下selectPopupWindow.setBackgroundDrawable(new BitmapDrawable()); }/*** 显示PopupWindow窗口** @param popupwindow*/public void popupWindwShowing() {//将selectPopupWindow作为parent的下拉框显示,并指定selectPopupWindow 在Y方向上向上偏移3pix,//这是为了防止下拉框与文本框之间产生缝隙,影响界面美化//(是否会产生缝隙,及产生缝隙的大小,可能会根据机型、Android系统版本不同而异吧,不太清楚)selectPopupWindow.showAsDropDown(parent,0,-3);}/*** PopupWindow消失*/public void dismiss(){selectPopupWindow.dismiss();}/*** 处理Hander消息*/@Overridepublic boolean handleMessage(Message message) {Bundle data = message.getData();switch(message.what){case 1://选中下拉项,下拉框消失int selIndex = data.getInt("selIndex");et.setText(datas.get(selIndex));dismiss();break;case 2://移除下拉项数据int delIndex = data.getInt("delIndex");datas.remove(delIndex);//刷新下拉列表optionsAdapter.notifyDataSetChanged();break;}return false;}}自定义适配器Adapter代码:package com.zw.select;import java.util.ArrayList;import android.app.Activity;import android.os.Bundle;import android.os.Handler;import android.os.Message;import youtInflater;import android.view.View;import android.view.ViewGroup;import android.widget.BaseAdapter;import android.widget.ImageView;import android.widget.TextView;//自定义适配器Adapterpublic class OptionsAdapter extends BaseAdapter {private ArrayList<String> list = new ArrayList<String>();private Activity activity = null;private Handler handler;/*** 自定义构造方法* @param activity* @param handler* @param list*/public OptionsAdapter(Activity activity,Handlerhandler,ArrayList<String> list){t his.activity = activity;t his.handler = handler;t his.list = list;}@Overridepublic int getCount() {return list.size();}@Overridepublic Object getItem(int position) {return list.get(position);}@Overridepublic long getItemId(int position) {return position;}@Overridepublic View getView(final int position, View convertView, ViewGroup parent) {ViewHolder holder = null;if (convertView == null) {holder = new ViewHolder();//下拉项布局convertView =LayoutInflater.from(activity).inflate(yout.option_item, null);holder.textView = (TextView)convertView.findViewById(R.id.item_text);holder.imageView = (ImageView)convertView.findViewById(R.id.delImage);convertView.setTag(holder);} else {holder = (ViewHolder) convertView.getTag();}holder.textView.setText(list.get(position));//为下拉框选项文字部分设置事件,最终效果是点击将其文字填充到文本框holder.textView.setOnClickListener(new View.OnClickListener() { @Overridepublic void onClick(View v) {Message msg = new Message();Bundle data = new Bundle();//设置选中索引data.putInt("selIndex", position);msg.setData(data);msg.what = 1;//发出消息handler.sendMessage(msg);}});//为下拉框选项删除图标部分设置事件,最终效果是点击将该选项删除holder.imageView.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View v) {Message msg = new Message();Bundle data = new Bundle();//设置删除索引data.putInt("delIndex", position);msg.setData(data);msg.what = 2;//发出消息handler.sendMessage(msg);}});return convertView;}}class ViewHolder {TextView textView;ImageView imageView;}主界面布局select.xml文件:<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#EEEED1"><LinearLayout android:id="@+id/parent"android:layout_width="wrap_content"android:layout_height="wrap_content"android:orientation="horizontal"android:layout_marginTop="50dp" android:layout_marginLeft="30dp"><EditText android:id="@+id/edittext"android:layout_width="200dp" android:singleLine="true"android:layout_height="40dp"android:background="@drawable/bg1" android:paddingLeft="3dp"/><ImageView android:id="@+id/btn_select"android:layout_width="30dp" android:layout_height="40dp"android:src="@drawable/img1"android:scaleType="fitXY"/></LinearLayout><Button android:id="@+id/refresh"android:layout_width="wrap_content" android:layout_height="45dp"android:text="恢复"android:textColor="#000000"android:textSize="20sp"android:layout_marginTop="30dp"android:layout_marginLeft="30dp"/></LinearLayout>PopupWindow浮动下拉框布局options.xml文件:<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:orientation="vertical"android:layout_width="fill_parent"android:layout_height="wrap_content"android:gravity="center_horizontal"><ListView android:id="@+id/list"android:layout_width="fill_parent"android:layout_height="wrap_content"android:cacheColorHint="#00000000"></ListView></LinearLayout>下拉选项布局option_item.xml文件:<?xml version="1.0"encoding="utf-8"?><LinearLayoutxmlns:android="/apk/res/android"android:layout_width="fill_parent"android:layout_height="fill_parent"android:background="#235654"><RelativeLayoutandroid:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center_vertical"android:minHeight="40dp"><ImageView android:id="@+id/delImage"android:layout_width="20dp" android:layout_height="wrap_content"android:src="@drawable/del"android:textSize="18sp"android:layout_alignParentRight="true"android:layout_marginRight="10dp"/><TextView android:id="@+id/item_text"android:layout_height="wrap_content"android:layout_width="fill_parent"android:layout_toLeftOf="@id/delImage"android:paddingLeft="5dp"android:layout_alignParentLeft="true"></TextView></RelativeLayout></LinearLayout>到此代码及布局文件基本都贴完了。
Android QQ SDK API
【QQ登录】Android_SDK使用说明QQ登录Android SDK以Jar包形式提供,封装了QQ登录的登录授权以及大部分OpenAPI,应用只需要修改少量代码,不需要理解验证授权流程,即可快速实现QQ登录功能。
Android平台上的应用,请在申请appid,appkey后,使用QQ互联提供的Android SDK。
注意:1. QQ登录Android SDK支持的Android版本:2.1及以上版本。
2. 支持的第三方浏览器:Android系统自带浏览器,Firefox,Opera Mobile。
3. 支持web view与浏览器两种方式,即支持跳转到手机浏览器上进行QQ登录与验证流程,开发者可在SDK包中选择浏览器模式即可,但浏览器方式用户跳跃较大,不建议使用。
4. 仅适用于移动应用,即基于【QQ登录】使用Implicit_Grant方式获取Access_Token接入的应用。
1. Android SDK 下载请到【QQ登录】SDK下载页面下载QQ登录Android SDK。
2. 创建工程及引用SDK源码文件以下以eclipse为开发的IDE进行范例说明:1. 创建一个工程,并把tencent_openapi.jar 放到lib中,如下图所示:2. 将tencent_openapi.jar加入编译路径中。
具体的操作步骤为:选中tencent_openapi.jar ,右键菜单中选择Build Path,选择Add to Build Path,如下图所示:看到类似以下的样子,说明已经成功将jar包加入build path :3. 修改必要的代码3.1 使用SDK提供的按钮样式SDK提供了大中小3种登录按钮,开发者可以在代码中设置按钮样式。
示例代码如下(在SDK包中的位置:\TAuthDemo\src\com\tencent\tauthdemo\TAuthDemoActivity.java )ImageViewloginBtn = (ImageView) findViewById(R.id.login);//大按钮loginBtn.setImageDrawable(TencentOpenRes.getBigLoginBtn(getAssets()));//中按钮//loginBtn.setImageDrawable(TencentOpenRes.getLoginBtn(getAssets()));//小按钮//loginBtn.setImageDrawable(TencentOpenRes.getSmallLoginBtn(getAssets()));3.2 获取access token(1)获取Access token 需要访问网络,所以需要修改AndroidManifest.xml,加入以下代码:<uses-permission android:name="android.permission.INTERNET"></uses-permission><activity android:name="com.tencent.tauth.TAuthView" android:launchMode="singleTask"> <intent-filter><action android:name="android.intent.action.VIEW" /><category android:name="android.intent.category.DEFAULT" /><category android:name="android.intent.category.BROWSABLE" /><!—这里的scheme必须与下面设置的CALLBACK一致,且全部小写。
Android开发系列(十一)QQ登陆界面——Android控件使用实例
Android开发系列(⼗⼀)QQ登陆界⾯——Android控件使⽤实例 这是新年第⼀弹,这⼏天家⾥有些闹⼼的事,直到现在还没解决,所以⼀直未更新博客。
不过这两个夜晚的时间做了⼀个QQ登录界⾯(2013版),其实我早就想做这么⼀个界⾯,只是前⼀段时间还没有复习太多的东西,现在在处理那些烦⼼事的零散时间做出来了基本的界⾯,也算是值得⾼兴的事情吧。
话不多说,这次因为可能讲的内容⽐较多,可能会分两次讲,所以⾸先先上图,以便对最终实现能够达到什么养的效果⼼中有数。
这是⼿机QQ2013官⽅版的登录界⾯:这个是我⾃⼰做出来的 QQ登录界⾯:当然与官⽅版相⽐还是有很⼤的差距,不过对于学习安卓控件的使⽤已经⾜够了。
为实现上述界⾯,需要有⼏个关键的知识点需要学习:⼀、实现圆⾓的效果——学会使⽤描述背景的drawable/中的 xml⽂件 需要在drawable⽂件夹中创建xml⽂件,⽂件的⽗控件类型为shape,在shape⽗控件中,有<solid/> <corners/> <stroke/> <padding/> 等属性,分别处理背景的填充颜⾊、边⾓的曲率、边框线的宽度和颜⾊、上下左右内边框(即背景超出使⽤改背景的空间的宽度)例如,若想实现⼀个圆⾓的ImageButton,可以创建⼀个 fillet_shape.xml⽂件<?xml version="1.0" encoding="utf-8"?><shape xmlns:android="/apk/res/android"><solid android:color="#ffffff"/><corners android:radius="10px"/><padding android:left="3dip" android:top="3dip" android:right="3dip" android:bottom="3dip"/></shape>然后在Activity类中⽤ImageButton的实例设置setBackgroundResource(); 或者在xml布局⽂件中在配置控件属性使⽤android:background="@drawable/fillet_shape"注意这⾥在配置好背景之后,在为ImageView设置显⽰的图⽚时,只能使⽤setImageResource()⽽不能使⽤setBackgroundResource();学会这点很重要,后⾯就可以举⼀反三,本例中使⽤该⽅法为 EditText设置了边框,为ListView的每⼀个Item设置了边框,为按钮设置了圆⾓背景。
详解android在mob平台实现qq登陆和分享
详解android在mob平台实现qq登陆和分享个⼈感觉mob平台功能还是⽐较强⼤的,很多功能都可以通过他们平台来实现。
建议仔细观看每⼀个步骤,如果⼀个步骤没处理好,可能就会让你的这个功能⽆法实现。
相信我⼀定可以成功的。
废话少说,先看⼀下效果:1.在mob平台配置ShareSDK环境1.如何在mob平台创建应⽤下⾯为我创建的应⽤,如图所⽰,我们选择接⼊的接⼝为ShareSDK2.获取你的App Key和App Secret(建议⽤⾃⼰的)获取你先创建应⽤的App Key和App Secret,这⾥主要告诉你在哪⾥找App Key和App Secret,因为等下需要⽤到。
3.点击SDK下载4.选择ShareSDK选择配置我们主要选择下⽅配置,然后点击保存配置(下⾯我会说明为什么只选择这些配置)。
5.点击下载,就会弹出下载提⽰6.关于为什么只选择这些配置?可以从上图中看出,⽆论是QQ还微博,微信等都需要获取他们平台的appId和appKey。
如果你直接使⽤平台的提供的appId和appKey是不能成功的。
如果我想要实现这些功能,我们得先去那些平台获取他的appId和appKey。
7.我创建的QQ开发者平台应⽤下⾯是我创建成功的应⽤,说实话QQ的这个服务确实挺慢的,⼀般审核需要⼏天,可以是免费的原因吧。
下⾯是创建应⽤的步骤。
1.成为个⼈开发者。
2.创建移动应⽤。
2.把ShareSDK部署到android1.新建⼀个moudle或者project这个就不细说,⽐较简单。
2.配置你的build.gradle(Project)⽂件如图所⽰,添加如图代码:代码如下:classpath "com.mob.sdk:MobSDK:2018.0319.1724"3.配置你的build.gradle(Module)⽂件1.⾸先加⼊如图代码根据你的情况选择:代码如下,因为我的版本是android studio 4.2最新版,加⼊⽅法如下:id 'com.mob.sdk'如果是其他android studio 3点多的版本,添加⽅法代码:apply plugin:'com.mob.sdk'2.其次加⼊下图代码加⼊代码如下(建议使⽤⾃⼰申请的appId和appKey,如果你使⽤的是我QQ申请的appId和appKey话,你是成功不了,关于为什么成功不了,我下⾯将会说明):MobSDK {fp true //严格模式}MobSDK {appKey "31c48ca47c70e"appSecret "2d7adbfcd73363bbbe41aeff60e41e4f"ShareSDK {loopShare truedevInfo {SinaWeibo {appKey "568898243"appSecret "38a4f8204cc784f81f9f0daaf31e02e3"callbackUri ""}QQ {appId "101906011"appKey "676d885e518445fed4d7d2341ff2d56f"}TencentWeibo {appKey "801307650"appSecret "ae36f4ee3946e1cbb98d6965b0b2ff5c"callbackUri ""}QZone {appId "100371282"appKey "aed9b0303e3ed1e27bae87c33761161d"}}}}3. 解释⼀下关于为什么成功不了下⾯我创建的应⽤我们可以看⼀下在QQ平台创建的应⽤包名和应⽤签名如下:然后我们在把他和我创建的android项⽬来对⽐⼀下:1.我的包名和他相同2.我们可以看⼀下我们的MD5是否相同第⼀步:如果查看你的项⽬的MD5找到图中的gradle点击图中红⾊圆圈处然后就可以查看MD5了第⼆步:将我的MD5的去掉':号',把⼤写改为⼩写,我们对⽐⼀下是相同的。
移动应用开发中的第三方登录集成教程
移动应用开发中的第三方登录集成教程随着移动互联网的快速发展,越来越多的应用程序需要用户登录来提供个性化的服务。
然而,用户登录的流程通常比较繁琐且容易导致用户流失。
为了简化用户登录流程,提高用户体验,第三方登录成为了开发者的首选。
本文将介绍移动应用开发中的第三方登录集成教程。
一、什么是第三方登录第三方登录是指用户可以通过第三方平台的账号登录到其他应用程序中,而不需要单独注册账号。
常见的第三方登录平台包括微信、QQ、微博等。
通过第三方登录,用户可以方便快捷地使用已有的账号登录其他应用,避免了记忆多个账号密码的烦恼。
二、为什么要集成第三方登录1. 提高用户体验:第三方登录可以避免用户繁琐的注册和登录流程,提高用户的使用便利性和体验。
2. 提高用户转化率:繁琐的注册流程往往是用户流失的主要原因之一,通过提供第三方登录选项,可以降低用户流失率,提高用户转化率。
3. 获取用户信息:通过第三方登录,开发者可以获取到用户在第三方平台上的基本信息,如昵称、头像等,为应用提供更个性化的服务。
三、第三方登录集成步骤1. 注册第三方平台账号:首先,开发者需要在目标第三方平台上注册一个开发者账号,获取到相应的App ID和App Secret。
2. 配置应用信息:在开发者平台上,配置应用的基本信息,包括应用名称、图标等。
3. 集成SDK:根据第三方平台提供的开发文档,将相应的SDK集成到应用程序中。
通常,第三方平台会提供相应的SDK和示例代码,开发者只需按照文档进行相应的配置和调用即可。
4. 授权登录:在应用中添加登录按钮,并在用户点击登录按钮时调用相应的第三方登录接口。
用户点击登录按钮后,会跳转到相应的第三方平台进行授权登录操作。
5. 获取用户信息:用户授权登录成功后,应用程序会收到相应的回调信息,开发者可以通过回调信息获取到用户在第三方平台上的基本信息。
6. 处理登录结果:根据第三方平台返回的登录结果,开发者可以进行相应的处理操作。
android实现QQ登录界面(大学作业一)
android实现QQ登录界⾯(⼤学作业⼀)实验项QQ登录界⾯⽬:实验地躬⾏楼718实验时间:2018.10.13点:⼀、实验⽬的:1.掌握Android中布局的概念和⽤法2.熟练掌握Android中Button、ImageView、EditText以及Toast的基本使⽤。
3. 熟练掌握偏好设置的⽤法⼆、实验内容与要求1.完成如下所⽰的QQ登录界⾯2.功能需求:2.1 界⾯需要做简单屏幕适配(weight属性)2.2 ⽤户名明⽂显⽰且只能是数字2.3 密码必须是密⽂显⽰,字符数字都可以。
2.4 ⽤户名或密码空,点击登录提⽰"⽤户名密码不能为空"2.5 ⽤户名和密码为指定时,点击按钮提⽰登录成功。
2.6 登录成功后,将⽤户名和密码保存在偏好设置中,2.7 退出QQ再次打开,记住⽤户名密码并显⽰出来三、实验步骤和结果:⽤户名是123,密码是password输⼊验证成功后即可显⽰登陆成功提⽰,然后保存到偏好设置中,以后开启⽤户名和密码就会显⽰在⽂本框内main_activity.xml:<android.support.constraint.ConstraintLayoutxmlns:android="/apk/res/android"xmlns:app="/apk/res-auto"xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"tools:context=".MainActivity"><LinearLayout xmlns:tools="/tools"android:layout_width="match_parent"android:layout_height="match_parent"android:background="@drawable/background_gradient"android:orientation="vertical"><ImageViewandroid:id="@+id/imageView1"android:layout_width="160dp"android:layout_height="0dp"android:layout_gravity="center_horizontal"android:layout_marginTop="10dp"android:layout_marginBottom="5dp" android:layout_weight="1"android:src="@drawable/logo" /><LinearLayoutandroid:layout_width="match_parent" android:layout_height="0dp" android:layout_weight="1"android:orientation="vertical"><EditTextandroid:id="@+id/username" android:layout_width="match_parent" android:layout_height="40dp" android:layout_below="@id/imageView1" android:layout_marginTop="5dp" android:background="#ffffff" android:hint="QQ/⼿机号"android:inputType="number" android:paddingLeft="12dp" android:textColor="#000000" /><EditTextandroid:id="@+id/pwd"android:layout_width="match_parent" android:layout_height="40dp" android:layout_below="@id/username" android:layout_marginTop="5dp" android:background="#ffffff" android:hint="密码"android:inputType="textPassword" android:paddingLeft="12dp" android:textColor="#000000" /><Buttonandroid:id="@+id/login"android:layout_width="match_parent" android:layout_height="40dp"android:layout_below="@id/pwd" android:layout_marginLeft="20dp"android:layout_marginTop="20dp" android:layout_marginRight="20dp" android:background="@drawable/shape" android:gravity="center"android:text="登录"android:textColor="#F9FAFB" /></LinearLayout></LinearLayout><LinearLayoutandroid:layout_width="match_parent"android:layout_height="0dp"android:layout_weight="1"android:padding="10dp"android:gravity="bottom"><TextViewandroid:id="@+id/textView2"android:layout_width="wrap_content"android:layout_height="wrap_content"android:gravity="center"android:text="⽆法登录"android:textColor="#0EB1EF" /><TextViewandroid:id="@+id/textView3"android:layout_width="match_parent"android:layout_height="wrap_content"android:gravity="right"android:text="新⽤户"android:textColor="#0EB1EF" /></LinearLayout></LinearLayout></android.support.constraint.ConstraintLayout> MainActivity.java主要代码:package com.lgqchinese.homework;import …public class MainActivity extends AppCompatActivity { private SharedPreferences sp;private SharedPreferences.Editor editor;private EditText userEdit;private EditText passEdit;private Button login;String userNameValue;String passwordValue;@Overrideprotected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(yout.activity_main);viewInfo();/*//隐藏titleif (getSupportActionBar() != null){ getSupportActionBar().hide();}*/}*/sp = getSharedPreferences("userInfo", 0);String name = sp.getString("USER_NAME", "");String pass = sp.getString("PASSWORD", "");userEdit.setText(name);passEdit.setText(pass);login.setOnClickListener(new View.OnClickListener() {@Overridepublic void onClick(View arg0) {userNameValue = userEdit.getText().toString();passwordValue = passEdit.getText().toString();//⽤户名或密码空,点击登录提⽰"⽤户名密码不能为空"if(userNameValue.equals("")||passwordValue.equals("")){Toast.makeText(MainActivity.this, "⽤户名或密码不能为空", Toast.LENGTH_SHORT).show(); }else {if (userNameValue.equals("123")&&passwordValue.equals("password")){//⽤户名和密码为指定时,点击按钮提⽰登录成功。
安卓应用使用QQ登录的申请流程
安卓应用使用QQ登录的申请流程1.为什么要在手机应用中加入QQ登录功能?QQ互联是腾讯开放平台为第三方网站和应用提供的开放接入方式,主要包含QQ登录、分享组件、赞组件和关注组件。
其中QQ登录成为国内最大第三方帐号登录体系,它可以让你打通QQ空间、朋友网、腾讯微博三大平台支持PC、移动应用等多终端接入。
因此,手机应用接入QQ登录,可以让用户只需要使用QQ账号密码就可登录,简化用户注册流程,更有效率的提高转化用户流量。
同时可借助QQ的用户基础,获取到网站所需的用户资料及传播资源,为你的应用带来更多发展的机遇和潜能。
2.QQ登录申请流程下面就Step By Step让你快速掌握安卓应用使用QQ登录的整个申请流程。
STEP1 进入官网进入QQ互联官网(ht tp://)后,如下图,页面上有硕大的‘手机接入’按钮,然后点击它,就会出现创建应用的界面(如没有登录,需登录;如果你第一次登录,还没有注册开发者信息会有开发者信息注册页面弹出)。
QQ登录如下图所示,是QQ互联中重要的模块,它可以让你打通QQ空间、朋友网、腾讯微博三大平台,并且支持PC、移动应用等多终端接入。
如何让你的安卓应用接入QQ登录,你可以点击此/intro/login链接,查看具体的接入步骤和方法。
STEP2 创建应用进入官网点击‘手机接入’按钮后,会弹出以下页面,如下图:填写好应用名称后,点击确定按钮你会到达自己的管理应用页面。
在创建了应用后,可以在管理应用中心管理应用,如下图所示:其中AppID是申请QQ登录成功后,分配给网站的appid,用来唯一标识网站,是一个整型的数字。
Key是申请QQ登录成功后,分配给网站的appkey。
appkey将在QQ登录过程中以及网站通过OpenAPI访问/修改空间受保护的资源时,用来计算签名值,以提高传输过程参数的防篡改性,是一个字符串。
注:这里的APP ID和key非常重要,不要泄露该信息。
STEP3 编辑应用信息使用QQ登录功能还需要填写应用的详细信息,可以点击左侧的“编辑信息”,如下图所示:点击编辑按钮,即可进入到编辑应用界面,如下图所示:你可以选择接入范围、修改名称、选择应用平台、设置应用链接地址、修改LOGO填写应用简介等功能,例如为你的安卓应用选择平台后,就会出现如图所以的设置页面:填写好信息后点击保存即可。
qq互联.Android_SDK_V2.0接口调用说明
Android_SDK_V2.0接口调用说明1.Tencent类接口调用说明接口主要有:●登录/校验登录态:login(Activity activity, String scope, IUiListener listener)●注销:logout(Context context)●设置QQ头像:setAvatar(Activity activity, Bundle params, IUiListener listener)●增量授权:reAuth(Activity activity, String scope, IUiListener listener)●分享消息到QQ:shareToQQ(Activity activity, Bundle params, IUiListener listener) ●分享消息到QQ空间:shareToQzone(Activity activity, Bundle params, IUiListenerlistener)调用以上SDK提供的接口后,会弹出相应的界面,以完成后续的操作。
接口的参数说明如下:参数参数说明activity调用者activity。
应用使用SDK时,会从应用自己的Activity跳转到SDK的Activity,应用调用SDK的Activity即为这里的调用者activity。
scope 应用需要获得哪些接口的权限,由“,”分隔(仅login接口需要)。
params 以K-V组合的字符串参数。
Params是一个Bundle类型的参数,里面以键值对(Key-value)的形式存储数据,应用传入的邀请分享等参数就是通过这种方式传递给SDK,然后由SDK发送到后台。
listener 回调接口,IUiListener实例。
1.1 登录/校验登录态通过调用Tencent类的login函数发起登录/校验登录态。
该接口具有两个作用,1. 如果开发者没有调用mTencent实例的setOpenId、setAccessToken接口,则该接口执行正常的登录操作;2. 如果开发者先调用mTencent 实例的setOpenId、setAccessToken接口,则该接口执行校验登录态的操作。
移动应用开发中的社交登录实现方法
移动应用开发中的社交登录实现方法随着智能手机的普及,移动应用的发展迅猛。
为了提升用户体验和便捷性,越来越多的移动应用开始使用社交登录功能,让用户可以直接通过自己在社交平台上的账号登录应用。
在这篇文章中,我们将讨论移动应用开发中的社交登录实现方法。
一、OAuth授权OAuth是一种用于授权的开放标准,已经被广泛应用于社交登录中。
应用程序可通过OAuth拿到用户授权的令牌(Token),然后使用该令牌通过API接口获取用户的基本信息。
在实际开发中,首先需要在社交平台上注册一个开发者账号,并创建一个应用。
接下来,通过应用管理后台获取到Client ID和Client Secret等必要的凭证信息。
然后,在移动应用中使用这些凭证信息,与社交平台进行通信,进行登录认证并获取授权。
二、用户授权流程用户在移动应用中选择社交登录时,通常会跳转到社交平台的登录页面,输入自己的账号和密码。
一般情况下,社交平台会要求用户授权,确认是否将自己的账户信息共享给应用程序。
一旦用户同意授权,应用程序将获得一个令牌,可以在后续的操作中使用该令牌来访问用户的相关信息。
三、社交平台SDK为了简化开发流程,许多社交平台提供了专门的SDK供开发者使用。
这些SDK通常包含了社交登录的相关接口和授权认证的实现细节,可以大大简化开发者的工作量。
使用SDK需要在开发者账号的管理后台中注册应用,并获取对应的App ID等信息。
然后,在移动应用中导入SDK并进行相应的配置。
通过SDK提供的接口,开发者可以实现社交登录的功能,并获取用户的信息。
四、存储和管理用户信息在移动应用中,一旦用户通过社交登录成功,应用程序就需要将用户的相关信息保存起来。
这些信息可以包括用户的昵称、头像、好友列表等。
开发者可以使用本地数据库、云存储或者其他合适的方式来存储这些信息,并在需要时进行读取和更新。
为了保障用户隐私和安全,开发者需要妥善处理和保护用户信息。
应用程序需要遵循相关的法律法规,并采取措施保障用户信息的安全。
QQ登录调试成功,经验分享
QQ登录调试成功,和大家分享一下最近在研究android上APP的QQ登录接入,经过一番研究和实践后,这里和大家分享下经验。
QQ互联作为企鹅公司联通其旗下QQ空间、朋友网、微博三大平台的开放平台,其功能十分强大。
使用其他提供的丰富API,可以充分使用企鹅公司的帐号体系和sns服务。
就Android 上的APP来说,已经有越来越多的应用接入了QQ互联,使用户可以直接用QQ号登陆,带来了登录体验上的提升。
虽然QQ互联功能强大,但是在android应用上接入还是比较简单,只需几步即可接入:第一步,注册。
访问QQ互联开放平台:/,填写应用的基本信息即可完成进行注册。
注册流程比较简单,注册完成后就会获得此应用对应的app id和app key。
第二步,下载android sdk和Demo。
下载地址:/wiki/%E3%80%90QQ%E7%99%BB%E5%BD%95%E3%80%91SDK%E4 %B8%8B%E8%BD%BD。
sdk是一个打包好的jar文件。
解压Demo后直接用Eclipse打开即看到全部源码,lib目录下面的tencent_openapi.jar即是sdk包,代码里面有详细的注释。
第三步,引入SDK。
把下载的sdk jar包拷贝到开发工程的lib目录下。
第四步,使用SDK。
启动SDK里面的TAuthView获取access token,然后调用api用已获取的access token 去交换OpenID,获取OpenID后即可开始使用QQ互联提供的丰富API。
这里重点分享下这个过程中需要注意的方面:1、和其他开放平台一样,要先了解该平台的接入规范和开发者协议,否则,你的接入会被停掉。
2、如果对其中的概念和术语不是很熟悉或了解,建议先了解OAuth协议3、获取到的access token具有3个月有效期,建议存储access token信息,以便后续调用API时使用。
在过期后提示用户再次授权。
移动应用开发中的第三方登录和分享功能实现
移动应用开发中的第三方登录和分享功能实现移动应用的发展日新月异,随之而来的是用户对于应用功能和用户体验的要求越来越高。
为了满足用户的需求,很多应用开始引入第三方登录和分享功能。
本文将探讨在移动应用开发中如何实现第三方登录和分享功能,以提升应用的用户体验和功能。
一、第三方登录功能的实现1. 用户登录体验的优化在传统的应用登录方式中,用户需要输入邮箱或手机号码、密码等信息进行注册和登录,这个过程通常会让用户感到繁琐和不便。
而第三方登录功能的引入,可以大大简化用户的登录过程。
用户可以利用已有的社交账号(如微信、微博、QQ 等)登录应用,无需额外的注册和密码设置,提高了用户的登录体验。
2. 接入第三方登录API要实现第三方登录功能,首先需要接入相应的第三方登录API,如微信开放平台、微博开放平台、QQ互联等。
开发者需要在这些平台上注册应用,并获取相应的AppID或AppKey等身份标识。
3. 调用第三方登录SDK接入API后,开发者需要在应用中调用对应的第三方登录SDK。
SDK通常会提供一些接口供开发者调用,以实现登录功能。
在用户点击第三方登录按钮后,应用会调起SDK,引导用户进行授权登录,并获取用户的基本信息。
4. 处理登录回调用户在第三方平台上完成授权登录后,第三方会将登录回调结果返回给应用。
应用需要处理这些登录回调,获取用户的信息并进行相应操作,比如将用户信息存储到本地数据库或服务器等。
此外,开发者还可以根据业务需求,自定义登录成功与否的提示界面。
二、第三方分享功能的实现1. 提高应用的曝光度通过引入第三方分享功能,用户可以将应用相关内容分享到社交平台上,从而提高应用的曝光度。
当用户分享应用的文章、图片、视频等内容时,可以携带自定义的标题、摘要和图片等信息,使分享内容更加吸引人。
2. 接入第三方分享API为了实现第三方分享功能,开发者需要接入相应的第三方分享API,如微信分享API、微博分享API、QQ分享API等。
QQ原生第三方登录分享接入
QQ原⽣第三⽅登录分享接⼊1,⾸页需要去腾讯开发者平台注册应⽤并且审核通过获取appid2,pod 'TencentOpenAPI-Unofficial', '~> 3.3.0'#import <TencentOpenAPI/QQApiInterface.h>#import <TencentOpenAPI/TencentOAuth.h>在xcode URLtype 加⼊tencent这个是appid identifier :com.tencent记得加⼊⽩名单<key>LSApplicationQueriesSchemes</key><array><string>wechat</string><string>weixin</string><string>sinaweibohd</string><string>sinaweibo</string><string>sinaweibosso</string><string>weibosdk</string><string>weibosdk2.5</string><string>mqqapi</string><string>mqq</string><string>mqqOpensdkSSoLogin</string><string>mqqconnect</string><string>mqqopensdkdataline</string><string>mqqopensdkgrouptribeshare</string><string>mqqopensdkfriend</string><string>mqqopensdkapi</string><string>mqqopensdkapiV2</string><string>mqqopensdkapiV3</string><string>mqqopensdkapiV4</string><string>mqzoneopensdk</string><string>wtloginmqq</string><string>wtloginmqq2</string><string>mqqwpa</string><string>mqzone</string><string>mqzonev2</string><string>mqzoneshare</string><string>wtloginqzone</string><string>mqzonewx</string><string>mqzoneopensdkapiV2</string><string>mqzoneopensdkapi19</string><string>mqzoneopensdkapi</string><string>mqqbrowser</string><string>mttbrowser</string></array>在appdelegate 回调@property (nonatomic,strong) TencentOAuth *oauth;<TencentSessionDelegate>- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {{//注意:初始化授权开发者需要在这⾥填⼊⾃⼰申请到的 AppID_oauth = [[TencentOAuth alloc] initWithAppId:QQ_Appid andDelegate:self];}- (BOOL)application:(UIApplication *)app openURL:(NSURL *)url options:(NSDictionary<UIApplicationOpenURLOptionsKey,id> *)options{ [TencentOAuth HandleOpenURL:url];return YES;}然后在第三⽅登录界⾯<TencentSessionDelegate>- (void)getAuthWithUserInfoFromQQ{self.tencentOAuth = [[TencentOAuth alloc]initWithAppId:@"appid" andDelegate:self];NSMutableArray *permission = [@[] mutableCopy]; permission = [NSMutableArrayarrayWithObjects:@"get_user_info",@"get_simple_userinfo",nil]; [self.tencentOAuth authorize:permission inSafari:NO];}#pragma mark --------- qq登录状态回调 TencentSessionDelegate------- (void)tencentDidNotNetWork{NSLog(@"没有⽹络,⽆法登录");}- (void)tencentDidLogin{if (_tencentOAuth.accessToken){NSLog(@"%@ == %@",_tencentOAuth.accessToken,_tencentOAuth.openId);[self.tencentOAuth getUserInfo];}else{NSLog(@"登录失败!没有获取到accessToken");}}/** * 登录失败后的回调 */- (void)tencentDidNotLogin:(BOOL)cancelled{if (cancelled){NSLog(@"⽤户取消登录");}else{NSLog(@"登录失败");}}- (void)getUserInfoResponse:(APIResponse *)response{NSLog(@"%@",response.jsonResponse);}分享QQApiTextObject *txtObj = [QQApiTextObject objectWithText:@"share text"];SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:txtObj];dispatch_async(dispatch_get_main_queue(), ^{// [QQApiInterface SendReqToQZone:req];QQApiSendResultCode sent = [QQApiInterface SendReqToQZone:req];//分享到QQ空间 [self handleSendResult:sent];qq好友QQApiTextObject *txtObj = [QQApiTextObject objectWithText:@"share text"];SendMessageToQQReq *req = [SendMessageToQQReq reqWithContent:txtObj];dispatch_async(dispatch_get_main_queue(), ^{// [QQApiInterface sendReq:req];QQApiSendResultCode sent = [QQApiInterface sendReq:req];//分享到QQ空间[self handleSendResult:sent];});- (void)handleSendResult:(QQApiSendResultCode)sendResult{switch (sendResult){case EQQAPIAPPNOTREGISTED:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"App未注册" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}case EQQAPIMESSAGECONTENTINVALID:case EQQAPIMESSAGECONTENTNULL:case EQQAPIMESSAGETYPEINVALID:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"发送参数错误" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}case EQQAPIQQNOTINSTALLED:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"您的设备未安装⼿机QQ" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}case EQQAPIQQNOTSUPPORTAPI:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"您的设备未安装⼿机QQ" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}case EQQAPISENDFAILD:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"发送失败" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}case EQQAPIVERSIONNEEDUPDATE:{UIAlertView *msgbox = [[UIAlertView alloc] initWithTitle:@"温馨提⽰" message:@"当前QQ版本太低,需要更新" delegate:nil cancelButtonTitle:@"取消" otherButtonTitles:nil];[msgbox show];break;}default:{break;}}}。
移动应用开发中的第三方登录集成方法
移动应用开发中的第三方登录集成方法随着智能手机的普及,移动应用的开发也成为了一个热门的领域。
许多应用都需要用户进行登录,并获取用户的个人信息,以提供个性化的服务。
为了简化用户的登录流程,许多开发者选择集成第三方登录功能,允许用户使用其它平台的账号进行登录。
本文将介绍移动应用开发中的第三方登录集成方法,并重点讨论几个常用的第三方登录平台。
一、集成第三方登录的优势第三方登录是指允许用户使用已有的第三方平台账号登录一个应用,例如使用微信、QQ、微博等账号登录一个应用。
与传统的账号密码登录相比,第三方登录具有以下几个优势。
首先,方便快捷。
用户可以直接使用已有的账号登录,无需额外注册,简化了登录流程,提高了用户体验。
其次,用户信息获取更全面。
许多第三方平台会要求用户授权,允许应用获取用户的个人信息。
这对于一些社交类应用来说尤为重要,可以帮助应用更好地了解用户的兴趣爱好,提供更贴心的服务。
最后,提高应用的可信度。
许多用户对于通过第三方平台登录的应用更加信任,相比于自己注册的账号更加安全可靠。
二、常用的第三方登录平台目前市场上有许多第三方登录平台可供开发者选择,下面将介绍几个常用的平台及其集成方法。
1. 微信登录微信登录是目前应用最广泛的第三方登录方式之一。
集成微信登录需要在微信开放平台注册开发者账号,并创建应用。
在应用中,可以获取到一个AppID,用于在应用中进行集成。
在移动应用中,可以通过调用微信提供的SDK来实现与微信的交互。
用户点击登录按钮后,应用会打开微信客户端进行授权,一旦用户授权成功,微信会返回一个授权code给应用。
应用拿到授权code后,可以通过微信提供的接口,获取用户的个人信息,例如昵称、头像等。
2. QQ登录QQ登录也是非常常见的第三方登录方式之一。
集成QQ登录需要在腾讯开放平台注册开发者账号,并创建应用。
在应用中,可以获取到一个AppID和AppKey,用于在应用中进行集成。
与微信登录类似,QQ登录也需要通过调用QQ提供的SDK来实现与QQ的交互。
一步一步教你在Android里创建自己的账号系统(一)
一步一步教你在Android 里创建自己的账号系统(一)大家在平时使用 Android 手机的时候,都会发现有些应用(例如 qq,微信,淘宝)为自己创建了账号系统,并且能够在设置页面看到他,可是当自己希望为自己的软件写一个账号系统的时候总是不知从何入手,现在我们就从头开始,一步一步打造属于自己应用的账号系统。
在进行设备账户管理的时候,我们会通过一个 AccountManager 类获取系统的账户管理类,获取的方法如下:1 AccountManager mAccountManager = (AccountManager)getSystemService(ACCOUNT_SERVICE); 或者1 A ccountManager accountManager = AccountManager.get(context);接下来我们需要通过 AccountManager 对象对账号系统进行操作。
1.获取账户信息首先我们来查看一下如何获取用户已有的账户信息,如果你希望读取系统当前的账户信息,那么你首先需要在 manifest 文件中申明一个读取账户的权限,如下:1 <uses-permission android:name="android.permission.GET_ACCOUNTS/"></uses-permission>(1)获取所有账户信息如果你希望获取到当前设备所有的账户信息,你可以使用:1 a ccountManager.getAccounts();(2)获取特定的账户信息如果你只希望获取自己或者特定的账户信息,你就应该使用:1 a ccountManager.getAccountsByType(com.kifile);后面的参数是你自己定义的账户类型,怎么设置我会在接下来的文章中写出来。
然后,我们就可以通过上面获取到的工具类,读取到手机上的账户信息了,这里我写了一个 ListView 的 Adapter 用于展示当前系统中的账号信息:1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 public class AccountAdapter extends BaseAdapter {private Account[] mAccounts;public AccountAdapter(Account[] accounts) { this.mAccounts = accounts;}@Overridepublic int getCount() {return mAccounts != null mAccounts.length : 0;}@Overridepublic Object getItem(int position) {return mAccounts[position];}@Overridepublic long getItemId(int position) {return 0;}@Overridepublic View getView(int position, View convertView, ViewGroup parent) {TextView tv = new TextView(getBaseContext());tv.setText(mAccounts[position].name + + mAccounts[position].type);return tv;}}29获取当前所有系统账户信息以及设置 ListView 的 Adapter 的方法如下:1 mListView.setAdapter(new AccountAdapter(mAccountManager.getAccounts()));显示效果如下:同你当前设备进行对比,你就会发现我们已经将当前所有的账户信息显示了出来,同样地如果你只希望显示部分的账户信息,你就可以通过 getAccountByType 获取对应的账户列表。
Android实现登录注册界面框架
Android实现登录注册界⾯框架⼩项⽬框架今天⽤QQ的时候想到了,不如⽤android studio 做⼀个类似于这样的登录软件。
当然QQ的实现的功能特别复杂,UI界⾯也很多,不是单纯的⼀时新奇就可以做出来的。
就是简单的实现了⼀些功能,做了三个界⾯;1.登录界⾯。
2.注册界⾯。
3.登陆后的界⾯。
功能描述登录按钮------按钮实现跳转到下⼀个界⾯,并且判断输⼊的账号、密码是否符合规则(不为空),提⽰,登陆成功或失败注册按钮------按钮实现跳转到注册界⾯登录界⾯main_activity.xml<LinearLayoutandroid:id="@+id/number"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/iv"android:layout_centerVertical="true"android:layout_marginBottom="5dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="15dp"android:background="#ffffff"><TextViewandroid:id="@+id/tv_number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:text="账号"android:textColor="#000"android:textSize="20dp" /><EditTextandroid:id="@+id/et_username"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:background="@null"android:padding="10dp" /></LinearLayout><LinearLayoutandroid:id="@+id/password"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@+id/number"android:layout_centerVertical="true"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:background="#ffffff"><TextViewandroid:id="@+id/tv_password"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:text="密码"android:textSize="20dp"android:textColor="#000" /><EditTextandroid:id="@+id/et_password"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_marginLeft="5dp"android:layout_toRightOf="@id/tv_password"android:background="@null"android:inputType="textPassword"android:padding="10dp" /></LinearLayout><Buttonandroid:id="@+id/button_login"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/password"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="60dp"android:background="#3c8dc4"android:text="登录"android:textColor="#ffffff"android:textSize="20dp" /><Buttonandroid:id="@+id/button_register"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/button_login"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="30dp"android:background="#b7585556"android:text="注册"android:textColor="#ffffff"android:textSize="20dp" /><CheckBoxandroid:checked="true"android:layout_width="wrap_content"android:layout_height="wrap_content"android:text="记住密码"android:id="@+id/checkBox"android:layout_below="@+id/password"android:layout_marginLeft="10dp"android:layout_marginTop="5dp"/>注册界⾯确定注册------按钮实现注册,判断以上四个注册信息是否符合规则,判断两次输⼊密码是否⼀样,并且不为空。
AndroidStudio实现简单的QQ登录界面的示例代码
AndroidStudio实现简单的QQ登录界⾯的⽰例代码⼀、项⽬概述QQ是我们⽇常⽣活使⽤最多的软件之⼀,包含登录界⾯和进⼊后的聊天界⾯、好友列表界⾯和空间动态界⾯等。
登录界⾯的制作⽐较简单,主要考验布局的使⽤,是实现QQ项⽬的第⼀步。
现在APP开发的⾸要⼯作都是实现登录页⾯,所以学会了QQ登录界⾯对以后的软件开发有着很重要的作⽤。
⼆、开发环境三、详细设计1、头像设计⾸先在layout⽂件⾥⾯选择了RelativeLayout(相对布局)作为整个页⾯的布局。
在顶端放置了⼀个ImageView控件,宽度和⾼度设置的都是70dp,⽔平居中设置为true。
然后使头像在整个页⾯下调⼀点,不要紧贴着顶端,所以layout_marginTop设置为40dp。
最后选择drawable⽂件夹中的head⽂件作为头像。
代码如下:<ImageViewandroid:id='@+id/iv'android:layout_width="70dp"android:layout_height="70dp"android:layout_centerHorizontal="true"android:layout_marginTop="40dp"android:background="@drawable/head"/>2、账号输⼊框利⽤LinearLayout(线性布局)作为账号输⼊框的外层布局,orientation设置的为⽔平排列。
放置了⼀个TextView控件,宽度和⾼度设置的wrap_content,即适应内容⼤⼩,显⽰⽂本“账号”。
紧接着放置⼀个EditText控件,⽤于输⼊账号内容,使⽤layout_toRightOf属性定位于账号的右侧。
<LinearLayoutandroid:id="@+id/number_11"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_below="@id/iv"android:layout_centerVertical="true"android:layout_marginBottom="5dp"android:layout_marginLeft="10dp"android:layout_marginRight="10dp"android:layout_marginTop="15dp"android:background="#ffffff"android:orientation="horizontal"><TextViewandroid:id="@+id/tv_number"android:layout_width="wrap_content"android:layout_height="wrap_content"android:padding="10dp"android:text="账号:"android:textColor="#000"android:textSize="20sp" /><EditTextandroid:id="@+id/et_number"android:layout_width="match_parent"android:layout_height="wrap_content"android:layout_toRightOf="@id/tv_number"android:layout_marginLeft="5dp"android:background="@null"android:inputType="text"android:padding="10dp" /></LinearLayout>3、密码输⼊框最外层依旧是LinearLayout(线性布局),整体放置在上⼀个LinearLayout的下⾯,控件排列依然为horizontal(⽔平)。
Android实现登录界面和功能实例
Android实现登录界⾯和功能实例近期⼀个android⼩程序须要登录功能,我简单实现了⼀下。
如今记录下来也当做个笔记,同⼀时候也希望能够相互学习。
所以,假设我的代码有问题,还各位请提出来。
多谢了!以下。
就简述⼀下此实例的主要内容:输⼊username和password 。
从本地⽂件userinfo.json中读取users。
推断此username是否在users中,假设不在则增加users,每次退出Activity都使⽤AES算法加密users。
然后保存到userinfo.json中。
username下拉菜单是由PopupWindow + ListView实现。
执⾏效果图:基本的代码:1、⽤户类Userpackage com.example.logindemo;import org.json.JSONException;import org.json.JSONObject;import android.util.Log;public class User {private String mId;private String mPwd;private static final String masterPassword = "FORYOU"; // AES加密算法的种⼦private static final String JSON_ID = "user_id";private static final String JSON_PWD = "user_pwd";private static final String TAG = "User";public User(String id, String pwd) {this.mId = id;this.mPwd = pwd;}public User(JSONObject json) throws Exception {if (json.has(JSON_ID)) {String id = json.getString(JSON_ID);String pwd = json.getString(JSON_PWD);// 解密后存放mId = AESUtils.decrypt(masterPassword, id);mPwd = AESUtils.decrypt(masterPassword, pwd);}}public JSONObject toJSON() throws Exception {// 使⽤AES加密算法加密后保存String id = AESUtils.encrypt(masterPassword, mId);String pwd = AESUtils.encrypt(masterPassword, mPwd);Log.i(TAG, "加密后:" + id + " " + pwd);JSONObject json = new JSONObject();try {json.put(JSON_ID, id);json.put(JSON_PWD, pwd);} catch (JSONException e) {e.printStackTrace();}return json;}public String getId() {return mId;}public String getPwd() {return mPwd;}}2、保存和载⼊本地User列表package com.example.logindemo;import java.io.BufferedReader;import java.io.FileInputStream;import java.io.FileNotFoundException;import java.io.IOException;import java.io.InputStreamReader;import java.io.OutputStream;import java.io.OutputStreamWriter;import java.io.Writer;import java.util.ArrayList;import org.json.JSONArray;import org.json.JSONException;import org.json.JSONTokener;import android.content.Context;import android.util.Log;public class Utils {private static final String FILENAME = "userinfo.json"; // ⽤户保存⽂件名称private static final String TAG = "Utils";/* 保存⽤户登录信息列表 */public static void saveUserList(Context context, ArrayList<User> users)throws Exception {/* 保存 */Log.i(TAG, "正在保存");Writer writer = null;OutputStream out = null;JSONArray array = new JSONArray();for (User user : users) {array.put(user.toJSON());}try {out = context.openFileOutput(FILENAME, Context.MODE_PRIVATE); // 覆盖 writer = new OutputStreamWriter(out);Log.i(TAG, "json的值:" + array.toString());writer.write(array.toString());} finally {if (writer != null)writer.close();}}/* 获取⽤户登录信息列表 */public static ArrayList<User> getUserList(Context context) {/* 载⼊ */FileInputStream in = null;ArrayList<User> users = new ArrayList<User>();try {in = context.openFileInput(FILENAME);BufferedReader reader = new BufferedReader(new InputStreamReader(in));StringBuilder jsonString = new StringBuilder();JSONArray jsonArray = new JSONArray();String line;while ((line = reader.readLine()) != null) {jsonString.append(line);}Log.i(TAG, jsonString.toString());jsonArray = (JSONArray) new JSONTokener(jsonString.toString()).nextValue(); // 把字符串转换成JSONArray对象for (int i = 0; i < jsonArray.length(); i++) {User user = new User(jsonArray.getJSONObject(i));users.add(user);}} catch (FileNotFoundException e) {e.printStackTrace();} catch (IOException e) {e.printStackTrace();} catch (JSONException e) {e.printStackTrace();} catch (Exception e) {e.printStackTrace();}return users;}}3、AES加密/解密package com.example.logindemo;import java.security.SecureRandom;import javax.crypto.Cipher;import javax.crypto.KeyGenerator;import javax.crypto.SecretKey;import javax.crypto.spec.IvParameterSpec;import javax.crypto.spec.SecretKeySpec;public class AESUtils {public static String encrypt(String seed, String cleartext)throws Exception {byte[] rawKey = getRawKey(seed.getBytes());byte[] result = encrypt(rawKey, cleartext.getBytes());return toHex(result);}public static String decrypt(String seed, String encrypted)throws Exception {byte[] rawKey = getRawKey(seed.getBytes());byte[] enc = toByte(encrypted);byte[] result = decrypt(rawKey, enc);return new String(result);}private static byte[] getRawKey(byte[] seed) throws Exception {KeyGenerator kgen = KeyGenerator.getInstance("AES");SecureRandom sr = SecureRandom.getInstance("SHA1PRNG", "Crypto"); sr.setSeed(seed);kgen.init(128, sr);SecretKey skey = kgen.generateKey();byte[] raw = skey.getEncoded();return raw;}private static byte[] encrypt(byte[] raw, byte[] clear) throws Exception {SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.ENCRYPT_MODE, skeySpec, new IvParameterSpec( new byte[cipher.getBlockSize()]));byte[] encrypted = cipher.doFinal(clear);return encrypted;}private static byte[] decrypt(byte[] raw, byte[] encrypted)throws Exception {SecretKeySpec skeySpec = new SecretKeySpec(raw, "AES");Cipher cipher = Cipher.getInstance("AES");cipher.init(Cipher.DECRYPT_MODE, skeySpec, new IvParameterSpec( new byte[cipher.getBlockSize()]));byte[] decrypted = cipher.doFinal(encrypted);return decrypted;}private static String toHex(String txt) {return toHex(txt.getBytes());}private static String fromHex(String hex) {return new String(toByte(hex));}private static byte[] toByte(String hexString) {int len = hexString.length() / 2;byte[] result = new byte[len];for (int i = 0; i < len; i++)result[i] = Integer.valueOf(hexString.substring(2 * i, 2 * i + 2),16).byteValue();return result;}private static String toHex(byte[] buf) {if (buf == null)return "";StringBuffer result = new StringBuffer(2 * buf.length);for (int i = 0; i < buf.length; i++) {appendHex(result, buf[i]);}return result.toString();}private final static String HEX = "0123456789ABCDEF";private static void appendHex(StringBuffer sb, byte b) {sb.append(HEX.charAt((b >> 4) & 0x0f)).append(HEX.charAt(b & 0x0f));}}4、LoginActivity.javapackage com.example.logindemo;import java.util.ArrayList;import android.app.Activity;import android.app.Dialog;import android.graphics.drawable.ColorDrawable;import android.os.Bundle;import android.text.Editable;import android.text.TextWatcher;import android.util.DisplayMetrics;import android.util.Log;import android.view.View;import android.view.ViewGroup;import android.view.Window;import android.view.WindowManager;import android.view.View.OnClickListener;import youtParams;import android.view.animation.Animation;import android.view.animation.AnimationUtils;import android.widget.AdapterView;import android.widget.AdapterView.OnItemClickListener;import android.widget.ArrayAdapter;import android.widget.Button;import android.widget.EditText;import android.widget.ImageView;import android.widget.LinearLayout;import android.widget.ListView;import android.widget.PopupWindow;import android.widget.PopupWindow.OnDismissListener;import android.widget.TextView;import android.widget.Toast;public class LoginActivity extends Activity implements OnClickListener,OnItemClickListener, OnDismissListener {protected static final String TAG = "LoginActivity";private LinearLayout mLoginLinearLayout; // 登录内容的容器private LinearLayout mUserIdLinearLayout; // 将下拉弹出窗体在此容器下⽅显⽰ private Animation mTranslate; // 位移动画private Dialog mLoginingDlg; // 显⽰正在登录的Dialogprivate EditText mIdEditText; // 登录ID编辑框private EditText mPwdEditText; // 登录password编辑框private ImageView mMoreUser; // 下拉图标private Button mLoginButton; // 登录buttonprivate ImageView mLoginMoreUserView; // 弹出下拉弹出窗的buttonprivate String mIdString;private String mPwdString;private ArrayList<User> mUsers; // ⽤户列表private ListView mUserIdListView; // 下拉弹出窗显⽰的ListView对象private MyAapter mAdapter; // ListView的监听器private PopupWindow mPop; // 下拉弹出窗@Overridepublic void onCreate(Bundle savedInstanceState) {super.onCreate(savedInstanceState);setContentView(yout.activity_login);initView();setListener();mLoginLinearLayout.startAnimation(mTranslate); // Y轴⽔平移动/* 获取已经保存好的⽤户password */mUsers = Utils.getUserList(LoginActivity.this);if (mUsers.size() > 0) {/* 将列表中的第⼀个user显⽰在编辑框 */mIdEditText.setText(mUsers.get(0).getId());mPwdEditText.setText(mUsers.get(0).getPwd());LinearLayout parent = (LinearLayout) getLayoutInflater().inflate(erifo_listview, null);mUserIdListView = (ListView) parent.findViewById(android.R.id.list); parent.removeView(mUserIdListView); // 必须脱离⽗⼦关系,不然会报错 mUserIdListView.setOnItemClickListener(this); // 设置点击事mAdapter = new MyAapter(mUsers);mUserIdListView.setAdapter(mAdapter);}/* ListView的适配器 */class MyAapter extends ArrayAdapter<User> {public MyAapter(ArrayList<User> users) {super(LoginActivity.this, 0, users);}public View getView(final int position, View convertView,ViewGroup parent) {if (convertView == null) {convertView = getLayoutInflater().inflate(yout.listview_item, null);}TextView userIdText = (TextView) convertView.findViewById(R.id.listview_userid);userIdText.setText(getItem(position).getId());ImageView deleteUser = (ImageView) convertView.findViewById(R.id.login_delete_user);deleteUser.setOnClickListener(new OnClickListener() {// 点击删除deleteUser时,在mUsers中删除选中的元素@Overridepublic void onClick(View v) {if (getItem(position).getId().equals(mIdString)) {// 假设要删除的⽤户Id和Id编辑框当前值相等,则清空mIdString = "";mPwdString = "";mIdEditText.setText(mIdString);mPwdEditText.setText(mPwdString);}mUsers.remove(getItem(position));mAdapter.notifyDataSetChanged(); // 更新ListView}});return convertView;}}private void setListener() {mIdEditText.addTextChangedListener(new TextWatcher() {public void onTextChanged(CharSequence s, int start, int before,int count) {mIdString = s.toString();}public void beforeTextChanged(CharSequence s, int start, int count, int after) {}public void afterTextChanged(Editable s) {}});mPwdEditText.addTextChangedListener(new TextWatcher() {public void onTextChanged(CharSequence s, int start, int before,int count) {mPwdString = s.toString();}public void beforeTextChanged(CharSequence s, int start, int count, int after) {}public void afterTextChanged(Editable s) {}});mLoginButton.setOnClickListener(this);mLoginMoreUserView.setOnClickListener(this);private void initView() {mIdEditText = (EditText) findViewById(R.id.login_edtId);mPwdEditText = (EditText) findViewById(R.id.login_edtPwd);mMoreUser = (ImageView) findViewById(R.id.login_more_user);mLoginButton = (Button) findViewById(R.id.login_btnLogin);mLoginMoreUserView = (ImageView) findViewById(R.id.login_more_user);mLoginLinearLayout = (LinearLayout) findViewById(R.id.login_linearLayout);mUserIdLinearLayout = (LinearLayout) findViewById(erId_LinearLayout);mTranslate = AnimationUtils.loadAnimation(this, R.anim.my_translate); // 初始化动画对象initLoginingDlg();}public void initPop() {int width = mUserIdLinearLayout.getWidth() - 4;int height = LayoutParams.WRAP_CONTENT;mPop = new PopupWindow(mUserIdListView, width, height, true);mPop.setOnDismissListener(this);// 设置弹出窗体消失时监听器// 注意要加这句代码,点击弹出窗体其他区域才会让窗体消失mPop.setBackgroundDrawable(new ColorDrawable(0xffffffff));}/* 初始化正在登录对话框 */private void initLoginingDlg() {mLoginingDlg = new Dialog(this, R.style.loginingDlg);mLoginingDlg.setContentView(yout.logining_dlg);Window window = mLoginingDlg.getWindow();youtParams params = window.getAttributes();// 获取和mLoginingDlg关联的当前窗体的属性,从⽽设置它在屏幕中显⽰的位置// 获取屏幕的⾼宽DisplayMetrics dm = new DisplayMetrics();getWindowManager().getDefaultDisplay().getMetrics(dm);int cxScreen = dm.widthPixels;int cyScreen = dm.heightPixels;int height = (int) getResources().getDimension(R.dimen.loginingdlg_height);// ⾼42dpint lrMargin = (int) getResources().getDimension(R.dimen.loginingdlg_lr_margin); // 左右边沿10dpint topMargin = (int) getResources().getDimension(R.dimen.loginingdlg_top_margin); // 上沿20dpparams.y = (-(cyScreen - height) / 2) + topMargin; // -199/* 对话框默认位置在屏幕中⼼,所以x,y表⽰此控件到"屏幕中⼼"的偏移量 */params.width = cxScreen;params.height = height;// width,height表⽰mLoginingDlg的实际⼤⼩mLoginingDlg.setCanceledOnTouchOutside(true); // 设置点击Dialog外部随意区域关闭Dialog}/* 显⽰正在登录对话框 */private void showLoginingDlg() {if (mLoginingDlg != null)mLoginingDlg.show();}/* 关闭正在登录对话框 */private void closeLoginingDlg() {if (mLoginingDlg != null && mLoginingDlg.isShowing())mLoginingDlg.dismiss();}@Overridepublic void onClick(View v) {switch (v.getId()) {case R.id.login_btnLogin:// 启动登录showLoginingDlg(); // 显⽰"正在登录"对话框,由于此Demo没有登录到webserver,所以效果可能看不出.能够结合情况使⽤ Log.i(TAG, mIdString + " " + mPwdString);if (mIdString == null || mIdString.equals("")) { // 账号为空时Toast.makeText(LoginActivity.this, "请输⼊账号", Toast.LENGTH_SHORT).show();} else if (mPwdString == null || mPwdString.equals("")) {// password为空时Toast.makeText(LoginActivity.this, "请输⼊password", Toast.LENGTH_SHORT).show();} else {// 账号和password都不为空时boolean mIsSave = true;try {Log.i(TAG, "保存⽤户列表");for (User user : mUsers) { // 推断本地⽂档是否有此ID⽤户if (user.getId().equals(mIdString)) {mIsSave = false;break;}}if (mIsSave) { // 将新⽤户增加usersUser user = new User(mIdString, mPwdString);mUsers.add(user);}} catch (Exception e) {e.printStackTrace();}closeLoginingDlg();// 关闭对话框Toast.makeText(this, "登录成功", Toast.LENGTH_SHORT).show();finish();}break;case R.id.login_more_user: // 当点击下拉栏if (mPop == null) {initPop();}if (!mPop.isShowing() && mUsers.size() > 0) {// Log.i(TAG, "切换为⾓向上图标");mMoreUser.setImageResource(R.drawable.login_more_down); // 切换图标 mPop.showAsDropDown(mUserIdLinearLayout, 2, 1); // 显⽰弹出窗体}break;default:break;}}@Overridepublic void onItemClick(AdapterView<?> parent, View view, int position,long id) {mIdEditText.setText(mUsers.get(position).getId());mPwdEditText.setText(mUsers.get(position).getPwd());mPop.dismiss();}/* PopupWindow对象dismiss时的事件 */@Overridepublic void onDismiss() {// Log.i(TAG, "切换为⾓向下图标");mMoreUser.setImageResource(R.drawable.login_more_up);}/* 退出此Activity时保存users */@Overridepublic void onPause() {super.onPause();try {Utils.saveUserList(LoginActivity.this, mUsers);} catch (Exception e) {e.printStackTrace();}}}其它⼀些布局和资源配置我就不具体列出了,想看的能够下载。
- 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
- 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
- 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。
背景
OAUTH开发授权协议,为用户资源的授权提供了一个安全开放而又简易的标准。
可以使用第三方的账户登陆另一个方的应用或服务,而不暴露给另一个应用该账户的信息。
现在已经得到广泛的应用,比如我们在互联网上可以看到很多服务可以通过第三方账号登录,这样既避免了用户注册的麻烦,也可以使用第三方的资源。
开发流程
一.QQ登录目前采用OAuth2.0标准协议来进行用户身份验证和获取用户授权。
整个流程如下所述,这里比如一个应用A可以使用QQ账户登陆。
1.用户访问客户端的应用,试图操作用户存放在服务提供方的资源。
比如用户用QQ账户登录应用A程序,同时可以获得用户昵称头像等保存在腾讯服务器的用户信息。
2.输入QQ账号后,应用A后向服务提供方(腾讯)(Request Token)。
请求一个临时令牌
3.服务提供方(腾讯)(应用A)的身份后,授予一个临时令牌。
验证客户端
4.客户端(应用A)获得临时令牌后,将用户引导至服务提供方(腾讯)的授权页面请求用户授权。
在这个过程中将临时令牌和客户端的回调连接发送给服务提供方(腾讯)。
5.用户在服务提供方(腾讯)的网页上输入用户名和密码,然后授权该客户端(应用A)访问所请求的资源。
6.授权成功后,服务提供方(腾讯)引导用户返回到客户端(应用A)提供的回调页面。
7.客户端(应用A)根据临时令牌从服务提供方(腾讯)那里获取访问令牌(Access Token)。
8.根据访问令牌(Access Token)获得对应用户身份的openid,
9.然后客户端(应用A)根据访问令牌(Access Token)与openid调用OpenAPI,来请求访问或修改用户授权的资源(比如昵称用户头像等经过用户授权的信息)。
10.拿到访问令牌(Access Token)之后,客户端(应用A)可以保存起来,下次就不用再向服务提供方(腾讯)请求授权,直接就可以使用该账户授权的资源,相当于保存了用户名和密码,但是真正的用户名和密码客户端(应用A)并不知道。
比如一个信息发布的网站,可以使用QQ账号登录,用户通过安全页面输入QQ账号信息后显示登陆成功,同时询问用户是否允许该网站使用用户的一些信息,比如资料,相册等,经过用户确认后该网站可以拿到用户授权的信息。
同时拿到访问令牌(Access Token),以后该网站就可以用这个访问获得该用户的这些授权信息,而不需要再次输入账户信息。
一般该网站也要提供删除这个访问令牌的入口。
这样就可以很方便的把用户愿意提供的信息拿到这个信息发布网站使用,而用户不需要再次登记录入。
二.QQ 为Android移动设备开发提供QQ登陆的开发包,对上述的过程进行的封装,对开发者来说可以方便的使用。
要真正开发一个使用QQ账户登录的App,就需要在腾讯社区开放平台注册应用,申请对应的appid和appkey,这个开发App时候要用到。
1.可以在腾讯开放API站点下载最新的QQ登录API库文件和Demo。
2.下载后的Demo工程如下,导入了库文件tencent_openapi.jar如下图一所示。
Demo介绍了两种登陆方式,手机浏览器和WebView,传入不同的参数,进入不同的登录方式,然后输入账户信息后会根据用户选择返回不同的结果。
开发者可以参考这些对应的代码即可完成授权登录的功能开发。
结束语
这里介绍了第三方应用如果使用QQ账户登录,目前国内很多应用和站点都提供了类似的服务,所以这时目前一种比较流行而且实用的方向,这里并没有对每个细节进行阐述,如有问题可以访问腾讯的QQ互联开放平台。