Android教程網
  1. 首頁
  2. Android 技術
  3. Android 手機
  4. Android 系統教程
  5. Android 游戲
 Android教程網 >> Android技術 >> 關於Android編程 >> Android實現第三方授權登錄、分享以及獲取用戶資料

Android實現第三方授權登錄、分享以及獲取用戶資料

編輯:關於Android編程

由於公司項目的需要,要實現在項目中使用第三方授權登錄以及分享文字和圖片等這樣的效果,幾經波折,查閱了一番資料,做了一個Demo。實現起來的效果還是不錯的,不敢獨享,決定寫一個總結的教程,供大家互相交流、學習和參考,只求能和大家共同進步。希望能多多支持!

這篇文章中,我們使用到了Share SDK,它是為iOS、Android、WP8的APP提供社會化功能的一個組件,目前支持如QQ、微信、新浪微博、騰訊微博、開心網、人人網、豆瓣、網易微博、搜狐微博、facebook、twitter、google+等國內外主流社交平台。

一、實現的效果圖
主界面效果圖

 

授權登錄頁面效果圖

點擊分享按鈕彈出分享分享界面       

有界面圖文分享,分享成功後會發送消息提示

二、項目結構目錄


三、編碼前的准備工作

1、獲取Libs    

Libs包含ShareSDK的類庫,具體包括三個文件夾,分別是ShareSDK的全局依賴庫、ShareSDK當前支持的所有平台工具庫和ShareSDK可視化UI的一些支持庫。“全局依賴庫”是集成ShareSDK的基礎,ShareSDK的任何平台都依賴於這個庫,而“ShareSDK-GUI”提供的是一個測欄控件和一個快捷分享工具,以方便讀者更快速地集成ShareSDK。

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(); 
  } 
   
} 

以上就是本文的全部內容,希望對大家的學習有所幫助,也希望大家多多支持本站。

  1. 上一頁:
  2. 下一頁:
熱門文章
閱讀排行版
Copyright © Android教程網 All Rights Reserved