Android實(shí)現(xiàn)第三方授權(quán)登錄、分享以及獲取用戶資料
由于公司項(xiàng)目的需要,要實(shí)現(xiàn)在項(xiàng)目中使用第三方授權(quán)登錄以及分享文字和圖片等這樣的效果,幾經(jīng)波折,查閱了一番資料,做了一個(gè)Demo。實(shí)現(xiàn)起來的效果還是不錯(cuò)的,不敢獨(dú)享,決定寫一個(gè)總結(jié)的教程,供大家互相交流、學(xué)習(xí)和參考,只求能和大家共同進(jìn)步。希望能多多支持!
這篇文章中,我們使用到了Share SDK,它是為iOS、Android、WP8的APP提供社會(huì)化功能的一個(gè)組件,目前支持如QQ、微信、新浪微博、騰訊微博、開心網(wǎng)、人人網(wǎng)、豆瓣、網(wǎng)易微博、搜狐微博、facebook、twitter、google+等國內(nèi)外主流社交平臺(tái)。
一、實(shí)現(xiàn)的效果圖
主界面效果圖

授權(quán)登錄頁面效果圖

點(diǎn)擊分享按鈕彈出分享分享界面

有界面圖文分享,分享成功后會(huì)發(fā)送消息提示

二、項(xiàng)目結(jié)構(gòu)目錄

三、編碼前的準(zhǔn)備工作
1、獲取Libs

Libs包含ShareSDK的類庫,具體包括三個(gè)文件夾,分別是ShareSDK的全局依賴庫、ShareSDK當(dāng)前支持的所有平臺(tái)工具庫和ShareSDK可視化UI的一些支持庫?!叭忠蕾噹臁笔羌蒘hareSDK的基礎(chǔ),ShareSDK的任何平臺(tái)都依賴于這個(gè)庫,而“ShareSDK-GUI”提供的是一個(gè)測欄控件和一個(gè)快捷分享工具,以方便讀者更快速地集成ShareSDK。
2、導(dǎo)入Libs
<1> 將“Libs\Global-Dependences”下的jar包復(fù)制到您的libs目錄下。
<2> 從“Libs\Platforms”中選擇您感興趣的平臺(tái),比方說“新浪微博”、“QQ空間”、“騰訊微博”等,復(fù)制相應(yīng)的壓縮包到你項(xiàng)目的libs目錄下并解壓
<3> 如果你決定使用shareSDK提供的快捷分享工具,還需要復(fù)制“Libs\ShareSDK-GUI”中復(fù)制“cn.sharesdk.onekeyshare.jar”到你的項(xiàng)目中。
<4> 一般來說,ADT會(huì)自動(dòng)將你添加到libs目錄下的jar包添加到“Android Dependencies”中。但是如果你的開發(fā)環(huán)境不能自動(dòng)加載ShareSDK的jar包到你的項(xiàng)目中,那么只能手動(dòng)添加,如下圖所示:
四、詳細(xì)的編碼實(shí)現(xiàn)
1、ShareSdK使用統(tǒng)一的格式管理你在不同平臺(tái)上注冊的開發(fā)者信息。這些信息都存放在項(xiàng)目的
“assets/ShareSDKDevInfor.xml”中,ShareSDKDevInfor.xml:
<?xml version="1.0" encoding="utf-8"?>
<DevInfor>
<!--說明:
1、表格中的第一項(xiàng)
<ShareSDK AppKey="api20" />
是必須的,其中的AppKey是你在Share SDK上注冊的開發(fā)者帳號(hào)的AppKey
2、所有集成到你項(xiàng)目的平臺(tái)都應(yīng)該為其在表格中填寫相對應(yīng)的開發(fā)者信息,以新浪微博為例:
<SinaWeibo
SortId="此平臺(tái)在分享列表中的位置,由開發(fā)者自行定義,可以是任何整型數(shù)字,數(shù)值越大越靠后"
AppKey="填寫你在新浪微博上注冊的AppKey"
AppSecret="填寫你在新浪微博上注冊到的AppKey"
Id="自定義字段,整形,用于你項(xiàng)目中對此平臺(tái)的識(shí)別符"
RedirectUrl="填寫你在新浪微博上注冊的RedirectUrl" />
各個(gè)平臺(tái)注冊應(yīng)用信息的地址如下:
新浪微博:http://open.weibo.com
騰訊微博:http://dev.t.qq.com
QQ空間:http://connect.qq.com/intro/login/
網(wǎng)易微博:http://open.t.163.com
搜狐微博:http://open.t.sohu.com
豆瓣:http://developers.douban.com
人人網(wǎng):http://dev.renren.com
開心網(wǎng):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中添加的內(nèi)容也不一樣。但是首先你需要添加下面的權(quán)限列表:
<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" />
這些權(quán)限將允許你的項(xiàng)目和ShareSDK獲取連接網(wǎng)絡(luò)的權(quán)限、獲取你的設(shè)備網(wǎng)絡(luò)狀態(tài)的權(quán)限、實(shí)現(xiàn)https安全連接的權(quán)限、讀取手機(jī)設(shè)備狀態(tài)的權(quán)限和保存必要配置的權(quán)限。一般來說,即便不集成ShareSDK,大部分的項(xiàng)目也都會(huì)注冊申請這些權(quán)限。
注意:大家在加入這個(gè)"android.permission.WRITE_APN_SETTINGS"權(quán)限的時(shí)候,可能有些讀者的編譯器會(huì)報(bào)錯(cuò),博主就遇到了這樣的情況,這個(gè)是ADT Lint工具的問題。
解決的辦法是:依照下面的路徑“Window —> Preferences —> android—> lint error checking”打開lint的配置頁面,然后去掉頁面頂部的兩個(gè)勾選,之后再clean項(xiàng)目就能處理。如下圖所示:

3、其次,為了授權(quán)操作可以順利完成,需要在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”下,因?yàn)樗赟hare-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="用戶授權(quán)登錄"
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="獲取授權(quán)用戶資料"
android:textSize="16dp" />
</RelativeLayout>
5、用戶授權(quán)登錄的布局頁面,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包下封裝的一個(gè)標(biāo)題欄-->
<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包下封裝的一個(gè)標(biāo)題欄-->
<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包下封裝的一個(gè)標(biāo)題欄-->
<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;
//定義"賬號(hào)登陸"按鈕,"有分享界面按鈕","無分享界面"按鈕,"得到用戶資料"按鈕
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);
}
/**
* 初始化數(shù)據(jù)
*/
private void initData(){
//設(shè)置按鈕監(jiān)聽事件
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;
}
}
/**
* 按鈕監(jiān)聽事件
*/
@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);
// 分享時(shí)Notification的圖標(biāo)
i.putExtra("notif_icon", R.drawable.ic_launcher);
// 分享時(shí)Notification的標(biāo)題
i.putExtra("notif_title", this.getString(R.string.app_name));
// title標(biāo)題,在印象筆記、郵箱、信息、微信(包括好友和朋友圈)、人人網(wǎng)和QQ空間使用,否則可以不提供
i.putExtra("title", this.getString(R.string.share));
// titleUrl是標(biāo)題的網(wǎng)絡(luò)鏈接,僅在人人網(wǎng)和QQ空間使用,否則可以不提供
i.putExtra("titleUrl", "http://sharesdk.cn");
// text是分享文本,所有平臺(tái)都需要這個(gè)字段
i.putExtra("text", this.getString(R.string.share_content));
// imagePath是本地的圖片路徑,所有平臺(tái)都支持這個(gè)字段,不提供,則表示不分享圖片
i.putExtra("imagePath", MainActivity.TEST_IMAGE);
// url僅在微信(包括好友和朋友圈)中使用,否則可以不提供
i.putExtra("url", "http://sharesdk.cn");
// thumbPath是縮略圖的本地路徑,僅在微信(包括好友和朋友圈)中使用,否則可以不提供
i.putExtra("thumbPath", MainActivity.TEST_IMAGE);
// appPath是待分享應(yīng)用程序的本地路勁,僅在微信(包括好友和朋友圈)中使用,否則可以不提供
i.putExtra("appPath", MainActivity.TEST_IMAGE);
// comment是我對這條分享的評論,僅在人人網(wǎng)和QQ空間使用,否則可以不提供
i.putExtra("comment", this.getString(R.string.share));
// site是分享此內(nèi)容的網(wǎng)站名稱,僅在QQ空間使用,否則可以不提供
i.putExtra("site", this.getString(R.string.app_name));
// siteUrl是分享此內(nèi)容的網(wǎng)站地址,僅在QQ空間使用,否則可以不提供
i.putExtra("siteUrl", "http://sharesdk.cn");
// 是否直接分享
i.putExtra("silent", silent);
this.startActivity(i);
}
/**
* 將action轉(zhuǎn)換為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() {
//結(jié)束ShareSDK的統(tǒng)計(jì)功能并釋放資源
AbstractWeibo.stopSDK(this);
super.onDestroy();
}
}
集成ShareSDK需要至少在兩個(gè)地方添加代碼,包括:
<1> 在onCreate中插入下面的代碼:
//初始化ShareSDK
AbstractWeibo.initSDK(this);
這行代碼會(huì)初始化ShareSDK,此后對ShareSDK的操作都依次為基礎(chǔ)。如果不在所有ShareSDK的操作之前調(diào)用這行代碼,會(huì)拋出空指針異常。
<2> 在項(xiàng)目的出口Activity的onDestroy方法的第一行插入下面的代碼:
protected void onDestroy() {
//結(jié)束ShareSDK的統(tǒng)計(jì)功能并釋放資源
AbstractWeibo.stopSDK(this);
super.onDestroy();
}
這行代碼會(huì)結(jié)束ShareSDK的統(tǒng)計(jì)功能并釋放資源。如果這行代碼沒有被調(diào)用,那么“應(yīng)用啟動(dòng)次數(shù)”的統(tǒng)計(jì)將不會(huì)準(zhǔn)確,因?yàn)閼?yīng)用可能從來沒有被關(guān)閉。
InitSDK是可以重復(fù)調(diào)用的,其實(shí)ShareSDK建議在你不確定的時(shí)候調(diào)用這個(gè)方法,來保證ShareSDK被正確初始化。而stopSDK一旦調(diào)用了,就必須重新調(diào)用InitSDK才能使用ShareSDK的功能,否則會(huì)出現(xiàn)空指針異常。
在這段代碼中,還使用到了快捷分享,如下圖所示,點(diǎn)擊按鈕彈出快捷分享界面:

什么是快捷分享呢?快捷分享是ShareSDK提供的一套基于其接口的GUI。通過簡單的配置,可以在不考慮平臺(tái)的情況下,調(diào)用很少的代碼,就完成分享的操作。快捷分享的jar包放在SDK解壓目錄的"Libs\ShareSDK-GUI"中,叫做"cn.sharesdk.oneshare.jar"??旖莘窒硎褂昧藘蓚€(gè)Activity,需要在AndroidManifest.xml中注冊這兩個(gè)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、帳號(hào)授權(quán)登錄界面,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
* 功能描述:授權(quán)和取消授權(quán)Activity,由于UI顯示需要授權(quán)過的平臺(tái)顯示賬戶的名稱,
* 因此此頁面事實(shí)上展示的是“獲取用戶資料”和“取消授權(quán)”兩個(gè)功能。
*/
public class AuthActivity extends Activity implements Callback, OnClickListener, WeiboActionListener {
//定義CheckedTextView對象
private CheckedTextView sinaCt,qzoneCt,tengxunCt,renrenCt;
//定義Handler對象
private Handler handler;
//定義標(biāo)題欄對象
private TitleLayout llTitle;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_auth);
initView();
initData();
}
/**
* 初始化組件
*/
private void initView(){
//實(shí)例化Handler對象并設(shè)置信息回調(diào)監(jiān)聽接口
handler = new Handler(this);
//得到標(biāo)題欄對象
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);
}
/**
* 初始化數(shù)據(jù)
*/
private void initData(){
llTitle.getBtnBack().setOnClickListener(new OnClickListener() {
@Override
public void onClick(View v) {
finish();
}
});
llTitle.getTvTitle().setText("用戶授權(quán)登錄");
//設(shè)置監(jiān)聽
sinaCt.setOnClickListener(this);
qzoneCt.setOnClickListener(this);
tengxunCt.setOnClickListener(this);
renrenCt.setOnClickListener(this);
//獲取平臺(tái)列表
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);
// 得到授權(quán)用戶的用戶名稱
String userName = weibos[i].getDb().get("nickname");
if (userName == null || userName.length() <= 0 || "null".equals(userName)) {
// 如果平臺(tái)已經(jīng)授權(quán)卻沒有拿到帳號(hào)名稱,則自動(dòng)獲取用戶資料,以獲取名稱
userName = getWeiboName(weibos[i]);
//添加平臺(tái)事件監(jiān)聽
weibos[i].setWeiboActionListener(this);
//顯示用戶資料,null表示顯示自己的資料
weibos[i].showUser(null);
}
ctv.setText(userName);
}
}
}
/**
* 在CheckedTextView組件中顯示授權(quán)用戶的名稱
*/
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;
}
/**
* 得到授權(quán)用戶的用戶名稱
*/
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);
}
/**
* 授權(quán)和取消授權(quán)的按鈕點(diǎn)擊監(jiān)聽事件
*/
@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);
}
/**
* 獲得授權(quán)
*/
private AbstractWeibo getWeibo(int vid) {
String name = null;
switch (vid) {
// 進(jìn)入新浪微博的授權(quán)頁面
case R.id.ctvSw:
name = SinaWeibo.NAME;
break;
// 進(jìn)入騰訊微博的授權(quán)頁面
case R.id.ctvTc:
name = TencentWeibo.NAME;
break;
// 進(jìn)入人人網(wǎng)的授權(quán)頁面
case R.id.ctvRr:
name = Renren.NAME;
break;
// 進(jìn)入QQ空間的授權(quán)頁面
case R.id.ctvQz:
name = QZone.NAME;
break;
}
if (name != null) {
return AbstractWeibo.getWeibo(this, name);
}
return null;
}
/**
* 授權(quán)成功的回調(diào)
* weibo - 回調(diào)的平臺(tái)
* action - 操作的類型
* res - 請求的數(shù)據(jù)通過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);
}
/**
* 授權(quán)失敗的回調(diào)
*/
@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);
}
/**
* 取消授權(quán)的回調(diào)
*/
@Override
public void onCancel(AbstractWeibo weibo, int action) {
Message msg = new Message();
msg.arg1 = 3;
msg.arg2 = action;
msg.obj = weibo;
handler.sendMessage(msg);
}
/**
* 處理從授權(quán)頁面返回的結(jié)果
*
* 如果獲取到用戶的名稱,則顯示名稱;否則如果已經(jīng)授權(quán),則顯示平臺(tái)名稱
*/
@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
* 功能描述:獲取用戶資料
*
* 啟動(dòng)頁面時(shí)傳遞一個(gè)int類型的字段type,用于標(biāo)記獲取自己的資料(type = 0)還是別人的資料(type = 1)。
* 如果嘗試獲取別人的資料,示例代碼會(huì)獲取不同平臺(tái)Share SDK的官方帳號(hào)的資料。
*
* 如果資料獲取成功,會(huì)通過{@link ShowInforPage}展示
*/
public class GetInforActivity extends Activity implements Callback, OnClickListener, WeiboActionListener {
//定義標(biāo)題欄布局對象
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(){
//得到標(biāo)題欄對象
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);
}
/**
* 初始化數(shù)據(jù)
*/
private void initData(){
//標(biāo)題欄設(shè)置返回按鈕監(jiān)聽
llTitle.getBtnBack().setOnClickListener(this);
//設(shè)置標(biāo)題欄的標(biāo)題文本
llTitle.getTvTitle().setText(R.string.get_my_info);
//設(shè)置監(jiān)聽
sinaBt.setOnClickListener(this);
renrenBt.setOnClickListener(this);
qzoneBt.setOnClickListener(this);
tengxunBt.setOnClickListener(this);
}
/**
* 點(diǎn)擊按鈕獲取授權(quán)用戶的資料
*/
@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);
}
/** 處理操作結(jié)果 */
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、這里還定義了一個(gè)Json解析類去讀取授權(quán)用戶的信息,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
* 功能描述:這是一個(gè)簡易的Json-HashMap轉(zhuǎn)換工具,可以將普通的json數(shù)據(jù)(字符串)
* 轉(zhuǎn)換為一個(gè)HashMap<Srting, Object>表格,也可以反過來操作。此外還支
* 持將json數(shù)據(jù)格式化。
*/
public class JsonUtils {
/**
* 將指定的json數(shù)據(jù)轉(zhuǎn)成 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>對象轉(zhuǎn)成json數(shù)據(jù)
*/
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;
}
/**
* 格式化一個(gè)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();
}
}
以上就是本文的全部內(nèi)容,希望對大家的學(xué)習(xí)有所幫助,也希望大家多多支持腳本之家。
相關(guān)文章
Android Presentation實(shí)現(xiàn)雙屏異顯
這篇文章主要為大家詳細(xì)介紹了Android Presentation實(shí)現(xiàn)雙屏異顯,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下2020-01-01
Android消息機(jī)制Handler用法總結(jié)
這篇文章介紹了Android消息機(jī)制Handler用法總結(jié),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧2021-11-11
Flutter使用?input?chip?標(biāo)簽組件示例詳解
這篇文章主要為大家介紹了Flutter使用?input?chip?標(biāo)簽組件示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-10-10
Kotlin協(xié)程Context應(yīng)用使用示例詳解
這篇文章主要為大家介紹了Kotlin協(xié)程Context應(yīng)用使用示例詳解,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進(jìn)步,早日升職加薪2022-12-12
Android中通過反射實(shí)現(xiàn)圓角ImageView代碼實(shí)例
這篇文章主要介紹了Android中通過反射實(shí)現(xiàn)圓角ImageView代碼實(shí)例,本文直接給出核心實(shí)現(xiàn)代碼,需要的朋友可以參考下2015-04-04

