【转】【Android应用开发详解】第01期:第三方授权认证(一)实现第三方授权登录、分享以及获取用户资料
转载请注明出处:http://blog.csdn.net/yangyu20121224/article/details/9057257
由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折,查阅了一番资料,做了一个Demo。实现起来的效果还是不错的,不敢独享,决定写一个总结的教程,供大家互相交流、学习和参考,博主只求能和大家共同进步。希望能多多支持!
这篇文章中,我们使用到了Share SDK,它是为iOS、Android、WP8的APP提供社会化功能的一个组件,目前支持如QQ、微信、新浪微博、腾讯微博、开心网、人人网、豆瓣、网易微博、搜狐微博、facebook、twitter、google+等国内外主流社交平台。
一、实现的效果图
主界面效果图 授权登录页面效果图
点击分享按钮弹出分享分享界面 有界面图文分享,分享成功后会发送消息提示
二、项目结构目录
三、编码前的准备工作
1、获取Libs
Libs包含ShareSDK的类库,具体包括三个文件夹,分别是ShareSDK的全局依赖库、ShareSDK当前支持的所有平台工具库和ShareSDK可视化UI的一些支持库。“全局依赖库”是集成ShareSDK的基础,ShareSDK的任何平台都依赖于这个库,而“ShareSDK-GUI”提供的是一个测栏控件和一个快捷分享工具,以方便读者更快速地集成ShareSDK。Libs下载地址
2、导入Libs
<1> 将“Libs\Global-Dependences”下的jar包复制到您的libs目录下。
<2> 从“Libs\Platforms”中选择您感兴趣的平台,比方说“新浪微博”、“QQ空间”、“腾讯微博”等,复制相应的压缩包到你项目的libs目录下并解压
<3> 如果你决定使用shareSDK提供的快捷分享工具,还需要复制“Libs\ShareSDK-GUI”中复制“cn.sharesdk.onekeyshare.jar”到你的项目中。
<4> 一般来说,ADT会自动将你添加到libs目录下的jar包添加到“Android Dependencies”中。但是如果你的开发环境不能自动加载ShareSDK的jar包到你的项目中,那么只能手动添加,如下图所示:
四、详细的编码实现
1、ShareSdK使用统一的格式管理你在不同平台上注册的开发者信息。这些信息都存放在项目的“assets/ShareSDKDevInfor.xml”中,ShareSDKDevInfor.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <DevInfor>
- <!--说明:
- 1、表格中的第一项
- <ShareSDK AppKey="api20" />
- 是必须的,其中的AppKey是你在Share SDK上注册的开发者帐号的AppKey
- 2、所有集成到你项目的平台都应该为其在表格中填写相对应的开发者信息,以新浪微博为例:
- <SinaWeibo
- SortId="此平台在分享列表中的位置,由开发者自行定义,可以是任何整型数字,数值越大越靠后"
- AppKey="填写你在新浪微博上注册的AppKey"
- AppSecret="填写你在新浪微博上注册到的AppKey"
- Id="自定义字段,整形,用于你项目中对此平台的识别符"
- RedirectUrl="填写你在新浪微博上注册的RedirectUrl" />
- 各个平台注册应用信息的地址如下:
- 新浪微博:http://open.weibo.com
- 腾讯微博:http://dev.t.qq.com
- QQ空间:http://connect.qq.com/intro/login/
- 网易微博:http://open.t.163.com
- 搜狐微博:http://open.t.sohu.com
- 豆瓣:http://developers.douban.com
- 人人网:http://dev.renren.com
- 开心网:http://open.kaixin001.com
- Instapaper:http://www.instapaper.com/main/request_oauth_consumer_token
- 有道云笔记:http://note.youdao.com/open/developguide.html#app
- facebook:https://developers.facebook.com
- twitter:https://dev.twitter.com
- 搜狐随身看:https://open.sohu.com
- QQ好友分享:http://mobile.qq.com/api/
- 微信:http://open.weixin.qq.com-->
- <ShareSDK
- AppKey = "api20"/> <!-- AppKey="104972cdd48" "23a9371d3a8"-->
- <SinaWeibo
- SortId="1"
- AppKey="3201194191"
- AppSecret="0334252914651e8f76bad63337b3b78f"
- Id="1"
- RedirectUrl="http://appgo.cn" />
- <TencentWeibo
- SortId="2"
- AppKey="801307650"
- AppSecret="ae36f4ee3946e1cbb98d6965b0b2ff5c"
- RedirectUri="http://sharesdk.cn"
- Id="2" />
- <QZone
- SortId="3"
- AppId="100371282"
- AppKey="aed9b0303e3ed1e27bae87c33761161d"
- Id="3"
- RedirectUrl="http://www.shareSDK.cn" />
- <Renren
- SortId="4"
- AppId="226427"
- ApiKey="fc5b8aed373c4c27a05b712acba0f8c3"
- Id="4"
- SecretKey="f29df781abdd4f49beca5a2194676ca4" />
- </DevInfor>
2、配置AndroidManifest.xml,不同的集成度需要在AndroidManifest.xml中添加的内容也不一样。但是首先你需要添加下面的权限列表:
- <uses-permission android:name="android.permission.INTERNET" />
- <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
- <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
- <uses-permission android:name="android.permission.WRITE_APN_SETTINGS" />
- <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
- <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
- <uses-permission android:name="android.permission.READ_PHONE_STATE" />
这些权限将允许你的项目和ShareSDK获取连接网络的权限、获取你的设备网络状态的权限、实现https安全连接的权限、读取手机设备状态的权限和保存必要配置的权限。一般来说,即便不集成ShareSDK,大部分的项目也都会注册申请这些权限。
注意:大家在加入这个"android.permission.WRITE_APN_SETTINGS"权限的时候,可能有些读者的编译器会报错,博主就遇到了这样的情况,这个是ADT Lint工具的问题。
解决的办法是:依照下面的路径“Window —> Preferences —> android—> lint error checking”打开lint的配置页面,然后去掉页面顶部的两个勾选,之后再clean项目就能处理。如下图所示:
3、其次,为了授权操作可以顺利完成,需要在application下注册下面的Activity:
- <activity
- android:name="cn.sharesdk.framework.AuthorizeActivity"
- android:configChanges="keyboardHidden|orientation"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.Translucent.NoTitleBar"
- android:windowSoftInputMode="stateHidden|adjustResize" >
- </activity>
AuthorizeActivity的路径是固定的,一定要在“cn.sharesdk.framework”下,因为他在Share-Core包中。
4、添加布局页面,首先是主界面的布局页面,activity_main.xml:
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- xmlns:tools="http://schemas.android.com/tools"
- android:layout_width="match_parent"
- android:layout_height="match_parent" >
- <Button
- android:id="@+id/btnLogin"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_above="@+id/btnShareAllGui"
- android:layout_centerHorizontal="true"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="用户授权登录"
- android:textSize="16dp"/>
- <Button
- android:id="@+id/btnShareAllGui"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_above="@+id/btnShareAll"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="分享全部(有分享界面)"
- android:textSize="16dp" />
- <Button
- android:id="@+id/btnShareAll"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_alignParentRight="true"
- android:layout_centerVertical="true"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="分享全部(无界面,直接分享)"
- android:textSize="16dp" />
- <Button
- android:id="@+id/btnUserInfo"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_below="@+id/btnShareAll"
- android:layout_margin="5dp"
- android:layout_marginTop="41dp"
- android:background="@drawable/btn_back"
- android:text="获取授权用户资料"
- android:textSize="16dp" />
- </RelativeLayout>
5、用户授权登录的布局页面,activity_auth.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="#fff5f5f5"
- android:orientation="vertical" >
- <!--ShareSDK-Core包下封装的一个标题栏-->
- <cn.sharesdk.framework.TitleLayout
- android:id="@+id/llTitle"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/title_back" />
- <LinearLayout
- android:id="@+id/llBody"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentLeft="true"
- android:layout_alignParentTop="true"
- android:layout_marginTop="58dp"
- android:orientation="vertical"
- android:padding="10dp" >
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:background="@drawable/list_item_first_normal"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
- <ImageView
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="10dp"
- android:scaleType="centerInside"
- android:src="@drawable/sina_weibo" />
- <CheckedTextView
- android:id="@+id/ctvSw"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_gravity="center_vertical"
- android:drawablePadding="10dp"
- android:drawableRight="@drawable/cb_drw"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:text="@string/not_yet_authorized"
- android:textColor="#ff000000"
- android:textSize="20dp" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:background="@drawable/list_item_middle_normal"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
- <ImageView
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="10dp"
- android:scaleType="centerInside"
- android:src="@drawable/tencent_weibo" />
- <CheckedTextView
- android:id="@+id/ctvTc"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_gravity="center_vertical"
- android:drawablePadding="10dp"
- android:drawableRight="@drawable/cb_drw"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:text="@string/not_yet_authorized"
- android:textColor="#ff000000"
- android:textSize="20dp" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:background="@drawable/list_item_middle_normal"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
- <ImageView
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="10dp"
- android:scaleType="centerInside"
- android:src="@drawable/renren" />
- <CheckedTextView
- android:id="@+id/ctvRr"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_gravity="center_vertical"
- android:drawablePadding="10dp"
- android:drawableRight="@drawable/cb_drw"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:text="@string/not_yet_authorized"
- android:textColor="#ff000000"
- android:textSize="20dp" />
- </LinearLayout>
- <LinearLayout
- android:layout_width="fill_parent"
- android:layout_height="50dp"
- android:background="@drawable/list_item_last_normal"
- android:paddingLeft="10dp"
- android:paddingRight="10dp" >
- <ImageView
- android:layout_width="30dp"
- android:layout_height="30dp"
- android:layout_gravity="center_vertical"
- android:layout_marginRight="10dp"
- android:scaleType="centerInside"
- android:src="@drawable/qzone" />
- <CheckedTextView
- android:id="@+id/ctvQz"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:layout_gravity="center_vertical"
- android:drawablePadding="10dp"
- android:drawableRight="@drawable/cb_drw"
- android:gravity="center_vertical"
- android:singleLine="true"
- android:text="@string/not_yet_authorized"
- android:textColor="#ff000000"
- android:textSize="20dp" />
- </LinearLayout>
- </LinearLayout>
- </RelativeLayout>
6、获得用户信息布局界面,activity_userinfo.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="#fff5f5f5"
- android:orientation="vertical" >
- <!--ShareSDK-Core包下封装的一个标题栏-->
- <cn.sharesdk.framework.TitleLayout
- android:id="@+id/llTitle"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/title_back" />
- <Button
- android:id="@+id/btnQz"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_centerVertical="true"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="@string/get_user_info_qz"
- android:textSize="16dp" />
- <Button
- android:id="@+id/btnRr"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_above="@+id/btnQz"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="@string/get_user_info_rr"
- android:textSize="16dp" />
- <Button
- android:id="@+id/btnSw"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_above="@+id/btnRr"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="@string/get_user_info_sw"
- android:textSize="16dp" />
- <Button
- android:id="@+id/btnTc"
- android:layout_width="fill_parent"
- android:layout_height="44dp"
- android:layout_below="@+id/btnQz"
- android:layout_centerHorizontal="true"
- android:layout_margin="5dp"
- android:background="@drawable/btn_back"
- android:text="@string/get_user_info_tc"
- android:textSize="16dp" />
- </RelativeLayout>
7、显示用户获得的信息布局界面,activity_userinfo.xml:
- <?xml version="1.0" encoding="utf-8"?>
- <RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android"
- android:layout_width="fill_parent"
- android:layout_height="fill_parent"
- android:background="#fff5f5f5"
- android:orientation="vertical" >
- <!--ShareSDK-Core包下封装的一个标题栏-->
- <cn.sharesdk.framework.TitleLayout
- android:id="@+id/llTitle"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:background="@drawable/title_back" />
- <ScrollView
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_alignParentBottom="true"
- android:layout_below="@id/llTitle"
- android:paddingBottom="10dp"
- android:paddingLeft="10dp"
- android:paddingTop="10dp" >
- <TextView
- android:id="@+id/tvJson"
- android:layout_width="fill_parent"
- android:layout_height="wrap_content"
- android:layout_marginRight="10dp"
- android:autoLink="all"
- android:background="@drawable/list_item_single_normal"
- android:textColor="#ff000000" />
- </ScrollView>
- </RelativeLayout>
8、主界面入口Activity类,MainActivity.java:
- package com.yangyu.activity;
- import java.io.File;
- import java.io.FileOutputStream;
- import android.app.Activity;
- import android.content.Intent;
- import android.graphics.Bitmap;
- import android.graphics.Bitmap.CompressFormat;
- import android.graphics.BitmapFactory;
- import android.os.Bundle;
- import android.os.Environment;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import cn.sharesdk.framework.AbstractWeibo;
- import cn.sharesdk.onekeyshare.ShareAllGird;
- import com.yangyu.mysharethings.R;
- /**
- * @author yangyu
- * 功能描述:主Activity类,程序的入口类
- */
- public class MainActivity extends Activity implements OnClickListener {
- //定义图片存放的地址
- public static String TEST_IMAGE;
- //定义"账号登陆"按钮,"有分享界面按钮","无分享界面"按钮,"得到用户资料"按钮
- private Button authLoginBtn,shareGuiBtn,shareBtn,getInfoBtn;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_main);
- //初始化ShareSDK
- AbstractWeibo.initSDK(this);
- initImagePath();
- initView();
- initData();
- }
- /**
- * 初始化组件
- */
- private void initView(){
- authLoginBtn = (Button)findViewById(R.id.btnLogin);
- shareGuiBtn = (Button)findViewById(R.id.btnShareAllGui);
- shareBtn = (Button)findViewById(R.id.btnShareAll);
- getInfoBtn = (Button)findViewById(R.id.btnUserInfo);
- }
- /**
- * 初始化数据
- */
- private void initData(){
- //设置按钮监听事件
- authLoginBtn.setOnClickListener(this);
- shareGuiBtn.setOnClickListener(this);
- shareBtn.setOnClickListener(this);
- getInfoBtn.setOnClickListener(this);
- }
- /**
- * 初始化分享的图片
- */
- private void initImagePath() {
- try {//判断SD卡中是否存在此文件夹
- if (Environment.MEDIA_MOUNTED.equals(Environment.getExternalStorageState())
- && Environment.getExternalStorageDirectory().exists()) {
- TEST_IMAGE = Environment.getExternalStorageDirectory().getAbsolutePath() + "/pic.png";
- }
- else {
- TEST_IMAGE = getApplication().getFilesDir().getAbsolutePath() + "/pic.png";
- }
- File file = new File(TEST_IMAGE);
- //判断图片是否存此文件夹中
- if (!file.exists()) {
- file.createNewFile();
- Bitmap pic = BitmapFactory.decodeResource(getResources(), R.drawable.pic);
- FileOutputStream fos = new FileOutputStream(file);
- pic.compress(CompressFormat.JPEG, 100, fos);
- fos.flush();
- fos.close();
- }
- } catch(Throwable t) {
- t.printStackTrace();
- TEST_IMAGE = null;
- }
- }
- /**
- * 按钮监听事件
- */
- @Override
- public void onClick(View v) {
- switch (v.getId()) {
- case R.id.btnLogin:
- startActivity(new Intent(MainActivity.this,AuthActivity.class));
- break;
- case R.id.btnShareAllGui:
- showGrid(false);
- break;
- case R.id.btnShareAll:
- showGrid(true);
- break;
- case R.id.btnUserInfo:
- // 获取自己的资料
- Intent i = new Intent(this, GetInforActivity.class);
- startActivity(i);
- break;
- default:
- break;
- }
- }
- /**
- * 使用快捷分享完成图文分享
- */
- private void showGrid(boolean silent) {
- Intent i = new Intent(this, ShareAllGird.class);
- // 分享时Notification的图标
- i.putExtra("notif_icon", R.drawable.ic_launcher);
- // 分享时Notification的标题
- i.putExtra("notif_title", this.getString(R.string.app_name));
- // title标题,在印象笔记、邮箱、信息、微信(包括好友和朋友圈)、人人网和QQ空间使用,否则可以不提供
- i.putExtra("title", this.getString(R.string.share));
- // titleUrl是标题的网络链接,仅在人人网和QQ空间使用,否则可以不提供
- i.putExtra("titleUrl", "http://sharesdk.cn");
- // text是分享文本,所有平台都需要这个字段
- i.putExtra("text", this.getString(R.string.share_content));
- // imagePath是本地的图片路径,所有平台都支持这个字段,不提供,则表示不分享图片
- i.putExtra("imagePath", MainActivity.TEST_IMAGE);
- // url仅在微信(包括好友和朋友圈)中使用,否则可以不提供
- i.putExtra("url", "http://sharesdk.cn");
- // thumbPath是缩略图的本地路径,仅在微信(包括好友和朋友圈)中使用,否则可以不提供
- i.putExtra("thumbPath", MainActivity.TEST_IMAGE);
- // appPath是待分享应用程序的本地路劲,仅在微信(包括好友和朋友圈)中使用,否则可以不提供
- i.putExtra("appPath", MainActivity.TEST_IMAGE);
- // comment是我对这条分享的评论,仅在人人网和QQ空间使用,否则可以不提供
- i.putExtra("comment", this.getString(R.string.share));
- // site是分享此内容的网站名称,仅在QQ空间使用,否则可以不提供
- i.putExtra("site", this.getString(R.string.app_name));
- // siteUrl是分享此内容的网站地址,仅在QQ空间使用,否则可以不提供
- i.putExtra("siteUrl", "http://sharesdk.cn");
- // 是否直接分享
- i.putExtra("silent", silent);
- this.startActivity(i);
- }
- /**
- * 将action转换为String
- */
- public static String actionToString(int action) {
- switch (action) {
- case AbstractWeibo.ACTION_AUTHORIZING: return "ACTION_AUTHORIZING";
- case AbstractWeibo.ACTION_GETTING_FRIEND_LIST: return "ACTION_GETTING_FRIEND_LIST";
- case AbstractWeibo.ACTION_FOLLOWING_USER: return "ACTION_FOLLOWING_USER";
- case AbstractWeibo.ACTION_SENDING_DIRECT_MESSAGE: return "ACTION_SENDING_DIRECT_MESSAGE";
- case AbstractWeibo.ACTION_TIMELINE: return "ACTION_TIMELINE";
- case AbstractWeibo.ACTION_USER_INFOR: return "ACTION_USER_INFOR";
- case AbstractWeibo.ACTION_SHARE: return "ACTION_SHARE";
- default: {
- return "UNKNOWN";
- }
- }
- }
- protected void onDestroy() {
- //结束ShareSDK的统计功能并释放资源
- AbstractWeibo.stopSDK(this);
- super.onDestroy();
- }
- }
集成ShareSDK需要至少在两个地方添加代码,包括:
<1> 在onCreate中插入下面的代码:
- //初始化ShareSDK
- AbstractWeibo.initSDK(this);
这行代码会初始化ShareSDK,此后对ShareSDK的操作都依次为基础。如果不在所有ShareSDK的操作之前调用这行代码,会抛出空指针异常。
<2> 在项目的出口Activity的onDestroy方法的第一行插入下面的代码:
- protected void onDestroy() {
- //结束ShareSDK的统计功能并释放资源
- AbstractWeibo.stopSDK(this);
- super.onDestroy();
- }
这行代码会结束ShareSDK的统计功能并释放资源。如果这行代码没有被调用,那么
“应用启动次数”的统计将不会准确,因为应用可能从来没有被关闭。
InitSDK是可以重复调用的,其实ShareSDK建议在你不确定的时候调用这个方法,
来保证ShareSDK被正确初始化。而stopSDK一旦调用了,就必须重新调用InitSDK才能使
用ShareSDK的功能,否则会出现空指针异常。
在这段代码中,还使用到了快捷分享,如下图所示,点击按钮弹出快捷分享界面:
什么是快捷分享呢?快捷分享是ShareSDK提供的一套基于其接口的GUI。通过简单的配置,可以在不考虑平台的情况下,调用很少的代码,就完成分享的操作。快捷分享的jar包放在SDK解压目录的"Libs\ShareSDK-GUI"中,叫做"cn.sharesdk.oneshare.jar"。快捷分享使用了两个Activity,需要在AndroidManifest.xml中注册这两个Activity:
- <activity
- android:name="cn.sharesdk.onekeyshare.ShareAllGird"
- android:configChanges="keyboardHidden|orientation"
- android:screenOrientation="portrait"
- android:theme="@android:style/Theme.Translucent.NoTitleBar"
- android:windowSoftInputMode="adjustPan|stateHidden" />
- <activity
- android:name="cn.sharesdk.onekeyshare.SharePage"
- android:configChanges="keyboardHidden|orientation"
- android:screenOrientation="portrait"
- android:windowSoftInputMode="stateHidden|adjustResize" />
9、帐号授权登录界面,AuthActivity.java:
- package com.yangyu.activity;
- import java.util.HashMap;
- import android.app.Activity;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Handler.Callback;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.CheckedTextView;
- import android.widget.Toast;
- import cn.sharesdk.framework.AbstractWeibo;
- import cn.sharesdk.framework.TitleLayout;
- import cn.sharesdk.framework.WeiboActionListener;
- import cn.sharesdk.renren.Renren;
- import cn.sharesdk.sina.weibo.SinaWeibo;
- import cn.sharesdk.tencent.qzone.QZone;
- import cn.sharesdk.tencent.weibo.TencentWeibo;
- import com.yangyu.mysharethings.R;
- /**
- * @author yangyu
- * 功能描述:授权和取消授权Activity,由于UI显示需要授权过的平台显示账户的名称,
- * 因此此页面事实上展示的是“获取用户资料”和“取消授权”两个功能。
- */
- public class AuthActivity extends Activity implements Callback, OnClickListener, WeiboActionListener {
- //定义CheckedTextView对象
- private CheckedTextView sinaCt,qzoneCt,tengxunCt,renrenCt;
- //定义Handler对象
- private Handler handler;
- //定义标题栏对象
- private TitleLayout llTitle;
- @Override
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_auth);
- initView();
- initData();
- }
- /**
- * 初始化组件
- */
- private void initView(){
- //实例化Handler对象并设置信息回调监听接口
- handler = new Handler(this);
- //得到标题栏对象
- llTitle = (TitleLayout) findViewById(R.id.llTitle);
- //得到组件对象
- sinaCt = (CheckedTextView)findViewById(R.id.ctvSw);
- qzoneCt = (CheckedTextView)findViewById(R.id.ctvQz);
- tengxunCt = (CheckedTextView)findViewById(R.id.ctvTc);
- renrenCt = (CheckedTextView)findViewById(R.id.ctvRr);
- }
- /**
- * 初始化数据
- */
- private void initData(){
- llTitle.getBtnBack().setOnClickListener(new OnClickListener() {
- @Override
- public void onClick(View v) {
- finish();
- }
- });
- llTitle.getTvTitle().setText("用户授权登录");
- //设置监听
- sinaCt.setOnClickListener(this);
- qzoneCt.setOnClickListener(this);
- tengxunCt.setOnClickListener(this);
- renrenCt.setOnClickListener(this);
- //获取平台列表
- AbstractWeibo[] weibos = AbstractWeibo.getWeiboList(this);
- for(int i = 0;i < weibos.length;i++){
- if (!weibos[i].isValid()) {
- continue;
- }
- CheckedTextView ctv = getView(weibos[i]);
- if (ctv != null) {
- ctv.setChecked(true);
- // 得到授权用户的用户名称
- String userName = weibos[i].getDb().get("nickname");
- if (userName == null || userName.length() <= 0 || "null".equals(userName)) {
- // 如果平台已经授权却没有拿到帐号名称,则自动获取用户资料,以获取名称
- userName = getWeiboName(weibos[i]);
- //添加平台事件监听
- weibos[i].setWeiboActionListener(this);
- //显示用户资料,null表示显示自己的资料
- weibos[i].showUser(null);
- }
- ctv.setText(userName);
- }
- }
- }
- /**
- * 在CheckedTextView组件中显示授权用户的名称
- */
- private CheckedTextView getView(AbstractWeibo weibo) {
- if (weibo == null) {
- return null;
- }
- String name = weibo.getName();
- if (name == null) {
- return null;
- }
- View v = null;
- if (SinaWeibo.NAME.equals(name)) {
- v = findViewById(R.id.ctvSw);
- }
- else if (TencentWeibo.NAME.equals(name)) {
- v = findViewById(R.id.ctvTc);
- }
- else if (Renren.NAME.equals(name)) {
- v = findViewById(R.id.ctvRr);
- }
- else if (QZone.NAME.equals(name)) {
- v = findViewById(R.id.ctvQz);
- }
- if (v == null) {
- return null;
- }
- if (! (v instanceof CheckedTextView)) {
- return null;
- }
- return (CheckedTextView) v;
- }
- /**
- * 得到授权用户的用户名称
- */
- private String getWeiboName(AbstractWeibo weibo) {
- if (weibo == null) {
- return null;
- }
- String name = weibo.getName();
- if (name == null) {
- return null;
- }
- int res = 0;
- if (SinaWeibo.NAME.equals(name)) {
- res = R.string.sinaweibo;
- }
- else if (TencentWeibo.NAME.equals(name)) {
- res = R.string.tencentweibo;
- }
- else if (Renren.NAME.equals(name)) {
- res = R.string.renren;
- }
- else if (QZone.NAME.equals(name)) {
- res = R.string.qzone;
- }
- if (res == 0) {
- return name;
- }
- return this.getResources().getString(res);
- }
- /**
- * 授权和取消授权的按钮点击监听事件
- */
- @Override
- public void onClick(View v) {
- AbstractWeibo weibo = getWeibo(v.getId());
- CheckedTextView ctv = (CheckedTextView) v;
- if (weibo == null) {
- ctv.setChecked(false);
- ctv.setText(R.string.not_yet_authorized);
- return;
- }
- if (weibo.isValid()) {
- weibo.removeAccount();
- ctv.setChecked(false);
- ctv.setText(R.string.not_yet_authorized);
- return;
- }
- weibo.setWeiboActionListener(this);
- weibo.showUser(null);
- }
- /**
- * 获得授权
- */
- private AbstractWeibo getWeibo(int vid) {
- String name = null;
- switch (vid) {
- // 进入新浪微博的授权页面
- case R.id.ctvSw:
- name = SinaWeibo.NAME;
- break;
- // 进入腾讯微博的授权页面
- case R.id.ctvTc:
- name = TencentWeibo.NAME;
- break;
- // 进入人人网的授权页面
- case R.id.ctvRr:
- name = Renren.NAME;
- break;
- // 进入QQ空间的授权页面
- case R.id.ctvQz:
- name = QZone.NAME;
- break;
- }
- if (name != null) {
- return AbstractWeibo.getWeibo(this, name);
- }
- return null;
- }
- /**
- * 授权成功的回调
- * weibo - 回调的平台
- * action - 操作的类型
- * res - 请求的数据通过res返回
- */
- @Override
- public void onComplete(AbstractWeibo weibo, int action,HashMap<String, Object> res) {
- Message msg = new Message();
- msg.arg1 = 1;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- }
- /**
- * 授权失败的回调
- */
- @Override
- public void onError(AbstractWeibo weibo, int action, Throwable t) {
- t.printStackTrace();
- Message msg = new Message();
- msg.arg1 = 2;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- }
- /**
- * 取消授权的回调
- */
- @Override
- public void onCancel(AbstractWeibo weibo, int action) {
- Message msg = new Message();
- msg.arg1 = 3;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- }
- /**
- * 处理从授权页面返回的结果
- *
- * 如果获取到用户的名称,则显示名称;否则如果已经授权,则显示平台名称
- */
- @Override
- public boolean handleMessage(Message msg) {
- AbstractWeibo weibo = (AbstractWeibo) msg.obj;
- String text = MainActivity.actionToString(msg.arg2);
- switch (msg.arg1) {
- case 1: { // 成功
- text = weibo.getName() + " completed at " + text;
- Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
- }
- break;
- case 2: { // 失败
- text = weibo.getName() + " caught error at " + text;
- Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
- return false;
- }
- case 3: { // 取消
- text = weibo.getName() + " canceled at " + text;
- Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
- return false;
- }
- }
- CheckedTextView ctv = getView(weibo);
- if (ctv != null) {
- ctv.setChecked(true);
- String userName = weibo.getDb().get("nickname"); // getAuthedUserName();
- if (userName == null || userName.length() <= 0
- || "null".equals(userName)) {
- userName = getWeiboName(weibo);
- }
- ctv.setText(userName);
- }
- return false;
- }
- }
10、获取用户信息界面,GetInfoActivity.java:
- package com.yangyu.activity;
- import java.util.HashMap;
- import android.app.Activity;
- import android.content.Intent;
- import android.os.Bundle;
- import android.os.Handler;
- import android.os.Handler.Callback;
- import android.os.Message;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.Button;
- import android.widget.Toast;
- import cn.sharesdk.framework.AbstractWeibo;
- import cn.sharesdk.framework.TitleLayout;
- import cn.sharesdk.framework.WeiboActionListener;
- import cn.sharesdk.renren.Renren;
- import cn.sharesdk.sina.weibo.SinaWeibo;
- import cn.sharesdk.tencent.qzone.QZone;
- import cn.sharesdk.tencent.weibo.TencentWeibo;
- import com.yangyu.mysharethings.R;
- /**
- * @author yangyu
- * 功能描述:获取用户资料
- *
- * 启动页面时传递一个int类型的字段type,用于标记获取自己的资料(type = 0)还是别人的资料(type = 1)。
- * 如果尝试获取别人的资料,示例代码会获取不同平台Share SDK的官方帐号的资料。
- *
- * 如果资料获取成功,会通过{@link ShowInforPage}展示
- */
- public class GetInforActivity extends Activity implements Callback, OnClickListener, WeiboActionListener {
- //定义标题栏布局对象
- private TitleLayout llTitle;
- private Button sinaBt,renrenBt,qzoneBt,tengxunBt;
- private Handler handler;
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- handler = new Handler(this);
- setContentView(R.layout.activity_userinfo);
- initView();
- initData();
- }
- /**
- * 初始化组件
- */
- private void initView(){
- //得到标题栏对象
- llTitle = (TitleLayout) findViewById(R.id.llTitle);
- //得到按钮对象
- sinaBt = (Button) findViewById(R.id.btnSw);
- renrenBt = (Button) findViewById(R.id.btnRr);
- qzoneBt = (Button) findViewById(R.id.btnQz);
- tengxunBt = (Button) findViewById(R.id.btnTc);
- }
- /**
- * 初始化数据
- */
- private void initData(){
- //标题栏设置返回按钮监听
- llTitle.getBtnBack().setOnClickListener(this);
- //设置标题栏的标题文本
- llTitle.getTvTitle().setText(R.string.get_my_info);
- //设置监听
- sinaBt.setOnClickListener(this);
- renrenBt.setOnClickListener(this);
- qzoneBt.setOnClickListener(this);
- tengxunBt.setOnClickListener(this);
- }
- /**
- * 点击按钮获取授权用户的资料
- */
- @Override
- public void onClick(View v) {
- if (v.equals(llTitle.getBtnBack())) {
- finish();
- return;
- }
- String name = null;
- switch (v.getId()) {
- case R.id.btnSw:
- name = SinaWeibo.NAME;
- break;
- case R.id.btnTc:
- name = TencentWeibo.NAME;
- break;
- case R.id.btnRr:
- name = Renren.NAME;
- break;
- case R.id.btnQz:
- name = QZone.NAME;
- break;
- }
- if (name != null) {
- AbstractWeibo weibo = AbstractWeibo.getWeibo(this, name);
- weibo.setWeiboActionListener(this);
- String account = null;
- weibo.showUser(account);
- }
- }
- public void onComplete(AbstractWeibo weibo, int action,HashMap<String, Object> res) {
- Message msg = new Message();
- msg.arg1 = 1;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- Message msg2 = new Message();
- msg2.what = 1;
- JsonUtils ju = new JsonUtils();
- String json = ju.fromHashMap(res);
- msg2.obj = ju.format(json);
- handler.sendMessage(msg2);
- }
- public void onError(AbstractWeibo weibo, int action, Throwable t) {
- t.printStackTrace();
- Message msg = new Message();
- msg.arg1 = 2;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- }
- public void onCancel(AbstractWeibo weibo, int action) {
- Message msg = new Message();
- msg.arg1 = 3;
- msg.arg2 = action;
- msg.obj = weibo;
- handler.sendMessage(msg);
- }
- /** 处理操作结果 */
- public boolean handleMessage(Message msg) {
- switch(msg.what) {
- case 1: {
- Intent i = new Intent(this, ShowInforActivity.class);
- i.putExtra("data", String.valueOf(msg.obj));
- startActivity(i);
- }
- break;
- default: {
- AbstractWeibo weibo = (AbstractWeibo) msg.obj;
- String text = MainActivity.actionToString(msg.arg2);
- switch (msg.arg1) {
- case 1: { // 成功
- text = weibo.getName() + " completed at " + text;
- }
- break;
- case 2: { // 失败
- text = weibo.getName() + " caught error at " + text;
- }
- break;
- case 3: { // 取消
- text = weibo.getName() + " canceled at " + text;
- }
- break;
- }
- Toast.makeText(this, text, Toast.LENGTH_SHORT).show();
- }
- break;
- }
- return false;
- }
- }
11、显示用户信息界面,ShowInfoActivity.java:
- package com.yangyu.activity;
- import android.app.Activity;
- import android.os.Bundle;
- import android.view.View;
- import android.view.View.OnClickListener;
- import android.widget.TextView;
- import cn.sharesdk.framework.TitleLayout;
- import com.yangyu.mysharethings.R;
- /**
- * @author yangyu
- * 功能描述:显示用户信息资料
- */
- public class ShowInforActivity extends Activity implements OnClickListener {
- private TitleLayout llTitle;
- protected void onCreate(Bundle savedInstanceState) {
- super.onCreate(savedInstanceState);
- setContentView(R.layout.activity_show_userinfo);
- llTitle = (TitleLayout) findViewById(R.id.llTitle);
- llTitle.getBtnBack().setOnClickListener(this);
- llTitle.getTvTitle().setText("用户资料");
- TextView tvJson = (TextView) findViewById(R.id.tvJson);
- tvJson.setText(getIntent().getStringExtra("data"));
- }
- @Override
- public void onClick(View v) {
- if (v.equals(llTitle.getBtnBack())) {
- finish();
- }
- }
- }
12、这里还定义了一个Json解析类去读取授权用户的信息,JsonUtils.java:
- package com.yangyu.activity;
- import java.util.ArrayList;
- import java.util.HashMap;
- import java.util.Iterator;
- import java.util.Map.Entry;
- import org.json.JSONArray;
- import org.json.JSONException;
- import org.json.JSONObject;
- /**
- * @author yangyu
- * 功能描述:这是一个简易的Json-HashMap转换工具,可以将普通的json数据(字符串)
- * 转换为一个HashMap<Srting, Object>表格,也可以反过来操作。此外还支
- * 持将json数据格式化。
- */
- public class JsonUtils {
- /**
- * 将指定的json数据转成 HashMap<String, Object>对象
- */
- public HashMap<String, Object> fromJson(String jsonStr) {
- try {
- if (jsonStr.startsWith("[")
- && jsonStr.endsWith("]")) {
- jsonStr = "{\"fakelist\":" + jsonStr + "}";
- }
- JSONObject json = new JSONObject(jsonStr);
- return fromJson(json);
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return new HashMap<String, Object>();
- }
- private HashMap<String, Object> fromJson(JSONObject json) throws JSONException {
- HashMap<String, Object> map = new HashMap<String, Object>();
- @SuppressWarnings("unchecked")
- Iterator<String> iKey = json.keys();
- while(iKey.hasNext()) {
- String key = iKey.next();
- Object value = json.opt(key);
- if (JSONObject.NULL.equals(value)) {
- value = null;
- }
- if (value != null) {
- if (value instanceof JSONObject) {
- value = fromJson((JSONObject)value);
- }
- else if (value instanceof JSONArray) {
- value = fromJson((JSONArray)value);
- }
- map.put(key, value);
- }
- }
- return map;
- }
- private ArrayList<Object> fromJson(JSONArray array)
- throws JSONException {
- ArrayList<Object> list = new ArrayList<Object>();
- for (int i = 0, size = array.length(); i < size; i++) {
- Object value = array.opt(i);
- if (value instanceof JSONObject) {
- value = fromJson((JSONObject)value);
- }
- else if (value instanceof JSONArray) {
- value = fromJson((JSONArray)value);
- }
- list.add(value);
- }
- return list;
- }
- /**
- * 将指定的HashMap<String, Object>对象转成json数据
- */
- public String fromHashMap(HashMap<String, Object> map) {
- try {
- return getJSONObject(map).toString();
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return "";
- }
- @SuppressWarnings("unchecked")
- private JSONObject getJSONObject(HashMap<String, Object> map)
- throws JSONException {
- JSONObject json = new JSONObject();
- for (Entry<String, Object> entry : map.entrySet()) {
- Object value = entry.getValue();
- if (value instanceof HashMap<?, ?>) {
- value = getJSONObject((HashMap<String, Object>)value);
- }
- else if (value instanceof ArrayList<?>) {
- value = getJSONArray((ArrayList<Object>)value);
- }
- json.put(entry.getKey(), value);
- }
- return json;
- }
- @SuppressWarnings("unchecked")
- private JSONArray getJSONArray(ArrayList<Object> list)
- throws JSONException {
- JSONArray array = new JSONArray();
- for (Object value : list) {
- if (value instanceof HashMap<?, ?>) {
- value = getJSONObject((HashMap<String, Object>)value);
- }
- else if (value instanceof ArrayList<?>) {
- value = getJSONArray((ArrayList<Object>)value);
- }
- array.put(value);
- }
- return array;
- }
- /**
- * 格式化一个json串
- */
- public String format(String jsonStr) {
- try {
- return format("", fromJson(jsonStr));
- } catch (Throwable t) {
- t.printStackTrace();
- }
- return "";
- }
- @SuppressWarnings("unchecked")
- private String format(String sepStr, HashMap<String, Object> map) {
- StringBuffer sb = new StringBuffer();
- sb.append("{\n");
- String mySepStr = sepStr + "\t";
- int i = 0;
- for (Entry<String, Object> entry : map.entrySet()) {
- if (i > 0) {
- sb.append(",\n");
- }
- sb.append(mySepStr).append('\"').append(entry.getKey()).append("\":");
- Object value = entry.getValue();
- if (value instanceof HashMap<?, ?>) {
- sb.append(format(mySepStr, (HashMap<String, Object>)value));
- }
- else if (value instanceof ArrayList<?>) {
- sb.append(format(mySepStr, (ArrayList<Object>)value));
- }
- else if (value instanceof String) {
- sb.append('\"').append(value).append('\"');
- }
- else {
- sb.append(value);
- }
- i++;
- }
- sb.append('\n').append(sepStr).append('}');
- return sb.toString();
- }
- @SuppressWarnings("unchecked")
- private String format(String sepStr, ArrayList<Object> list) {
- StringBuffer sb = new StringBuffer();
- sb.append("[\n");
- String mySepStr = sepStr + "\t";
- int i = 0;
- for (Object value : list) {
- if (i > 0) {
- sb.append(",\n");
- }
- sb.append(mySepStr);
- if (value instanceof HashMap<?, ?>) {
- sb.append(format(mySepStr, (HashMap<String, Object>)value));
- }
- else if (value instanceof ArrayList<?>) {
- sb.append(format(mySepStr, (ArrayList<Object>)value));
- }
- else if (value instanceof String) {
- sb.append('\"').append(value).append('\"');
- }
- else {
- sb.append(value);
- }
- i++;
- }
- sb.append('\n').append(sepStr).append(']');
- return sb.toString();
- }
- }
讲到这里关于这一篇的内容就差不多已经讲完了,下一篇是关于微信开放平台的授权以及分享,因为微信平台不同于其它第三方平台,实现起来稍微复杂一点,所以博主打算在下一篇的文章中详细讲解。这个下一篇文章估计要等到三天后了吧,博主和女友早就商量好趁着三天小长假出去散散心了,在这里祝大家端午节快乐!博主将会长期坚持更新关于Android、Java、Cocos2d-x、Unity3d等各个不同知识领域的实例讲解和开发!希望大家继续支持!
【转】【Android应用开发详解】第01期:第三方授权认证(一)实现第三方授权登录、分享以及获取用户资料的更多相关文章
- 《Android游戏开发详解》一1.7 控制流程第1部分——if和else语句
本节书摘来异步社区<Android游戏开发详解>一书中的第1章,第1.7节,译者: 李强 责编: 陈冀康,更多章节内容可以访问云栖社区"异步社区"公众号查看. 1.7 ...
- Android WebView 开发详解
Android WebView 开发详解 参见 http://blog.csdn.net/typename/article/details/39030091
- JMessage Android 端开发详解
目前越来越多的应用会需要集成即时通讯功能,这里就为大家详细讲一下如何通过集成 JMessage 来为你的 App 增加即时通讯功能. 首先,一个最基础的 IM 应用会需要有哪些功能? 用户注册 / 登 ...
- Android USB 开发详解
Android USB 开发详解 先附上 Android USB 官方文档 Android通过两种模式支持各种 USB 外设和 Android USB 附件(实现Android附件协议的硬件):USB ...
- 【Android应用开发详解】实现第三方授权登录、分享以及获取用户资料
由于公司项目的需要,要实现在项目中使用第三方授权登录以及分享文字和图片等这样的效果,几经波折,查阅了一番资料,做了一个Demo.实现起来的效果还是不错的,不敢独享,决定写一个总结的教程,供大家互相 ...
- Android WebView 开发详解(一)
转载请注明出处 http://blog.csdn.net/typename/article/details/39030091 powered by meichal zhao 概览: Android ...
- Android Widget 开发详解(二) +支持listView滑动的widget
转载请标明出处:http://blog.csdn.net/sk719887916/article/details/47027263 不少开发项目中都会有widget功能,别小瞧了它,他也是androi ...
- Android WebView 开发详解(三)
转载请注明出处 http://blog.csdn.net/typename/article/details/40302351 powered by miechal zhao 概览 Android ...
- Android WebView 开发详解(二)
转载请注明出处 http://blog.csdn.net/typename/article/details/39495409 powered by miechal zhao 概览: Androi ...
随机推荐
- java中System类简介(转)
上次面试中遇到的一个问题,问到System.out.println()中的out是不是内部类[不是内部类],当时就给问蒙了,直观感觉out应该是System类的一个属性,跟内部类有什么关系?而且之前整 ...
- Matlab.NET混合编程技巧之——直接调用Matlab内置函数(附源码)
原文:[原创]Matlab.NET混合编程技巧之--直接调用Matlab内置函数(附源码) 在我的上一篇文章[原创]Matlab.NET混编技巧之——找出Matlab内置函数中,已经大概的介绍了mat ...
- Spring Security 入门详解(转)
1.Spring Security介绍 Spring Security是基于spring的应用程序提供声明式安全保护的安全性框架,它提供了完整的安全性解决方案,能够在web请求级别和方法调用级别 处理 ...
- HTTPS背后的加密算法(转)
当你在浏览器的地址栏上输入https开头的网址后,浏览器和服务器之间会在接下来的几百毫秒内进行大量的通信.InfoQ的这篇文章对此有非常详细的描述.这些复杂的步骤的第一步,就是浏览器与服务器之间协商一 ...
- Oracle安装及使用入门
新手Oracle安装及使用入门 一.安装Oracle Step1 下载oracle压缩包并解压到同一文件夹下面 Step2 双击setup.exe进行安装 Step3:进入如下界面配置: 邮箱可不 ...
- 在MVC5中的使用Ninject
在MVC5中的使用 Ninject 从MVC3中就开始接触Ninject这个IOC工具.也一直是MVC Framework系列书籍中推荐的IOC工具,当然还有优秀的Autofac等.性能和使用上面个有 ...
- C# 你不能调用的问题剪贴板线程
最近在做一个项目,需要使用线程,并使用剪贴板,头发得到较少的数据在剪贴板上后,现在的孩子线程创建一个子线程,我特别困惑,上网查资料.最后,得到最终的.下面的例子现在将概括解: 第一步: public ...
- Access Toke调用受保护的API
ASP.NET Web API与Owin OAuth:使用Access Toke调用受保护的API 在前一篇博文中,我们使用OAuth的Client Credential Grant授权方式,在服务端 ...
- Linq入门演练---(1)基本用法-分组,排序,内连接
这一节大家共同学习下LINQ的基本用法,主要包括LINQ的分组,排序,和内外连接. 1.分组 基本语法: group element by key element 表示查询结果返回的元素,key表示 ...
- EntityFramework:状态变化与方法的关系
一.约定 OnModelCreated 有一些限制需要注意,例如: 1.表名不支持使用标签进行标注 2.最小长度在 OnModelCreated 中不支持 3.正则表达式在 O ...