Android應用開發中,第三方集成新浪微博(sinaWeiboSDK)的過程記錄


作為一個android開發人員,不可避免的要學會使用和集成第三方API的能力

而新浪微博作為現在最主要的新聞速遞媒體,使用十分普遍,並且提供了較為詳細的API接入方法,故此選擇集成sinaWeibiSdk.

 

step1.准備步驟:

首先要注冊成為sina開發者身份,並在sina的開發平台政策和指導下,創建和注冊自己將要集成的應用,其中包括sniaWeiboSdk下載,應用創建,獲取APP_KEY 和APP secret的信息等基本的集成信息准備。

 

step2.集成sdk內容到自己的project

注:具體的步驟在sina給出的開發者文檔中有詳細的實例和講解,這里僅僅記錄自己遇到的問題。

 

兩種sdk的權限范圍和導入方法:

1.weibosdkcore.jar包:適用於只需要授權、分享、網絡請求框架功能的項目

2.WeiboSDK工程(Library):適用於微博授權、分享,以及需要登陸按鈕、調用OpenAPI的項目

 

導入weibosdkcore.jar包的方法: 

切換project的顯示視角到project選項->直接將weibosdkcore.jar包文件復制粘貼到libs文件夾下->add as external Library->sync

 

將整個WeiboSDK工程(Library)作為library的方法:

 1.切換project的顯示視角到Android選項

2.將WeiboSDK工程整個目錄拷貝到和你自己的工程相同的目錄下/import new module

3.找到WeiboSDK項目的build.gradle文件夾,找到apply plugin: 'com.android.application' 這條設置選項,將這條選項更改為 apply plugin: 'com.android.library',然后選擇sync

4.點擊自己的項目->右鍵->open module setting ->選擇 Dependencies -> 加號,添加sinaSDK到Dependencies->sync

注:

1.兩種sdk同時導入工程會引發Exception,沒有找到解決辦法,由於SDK工程功能更加的全面,故嘗試刪除導入的weibosdkcore.jar包,sync/rebuild工程,即能同時運行。

 

具體的網絡數據交互,json數據解析,界面設計,用戶交互等在全部設計完成后,再行一次性更新。

————————————————————————————————————————————————————————————

接上文更新,要使用新浪微博的SDK,需要做一些准備工作,其中包括:

1.上文中提到的SDK工程導入,as Library

2.配置Constants類中的信息,此類中的信息在注冊應用的時候可以獲得,將對應的項目改為自己應用的數據(此數據需嚴格保密)

3.為了能夠順利使用SDK的相關API,在assets文件中,導入libweibosdkcore.co文件,並在manifests文件中注冊用來授權的Activity

注冊該Activity的代碼:(該Activity是作為授權切換界面的)

<activity android:name=".WeiboManager">
  <intent-filter>
   <action android:name="com.sina.weibo.sdk.action.ACTION_SDK_REQ_ACTIVITY" />

   <category android:name="android.intent.category.DEFAULT" />
   </intent-filter>
</activity>


以上准備工作完成后,下面這是用來獲取微博授權的Activity代碼

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.view.View;

public class MainActivity extends Activity {


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

    //獲取微博的Token信息(即為憑證)
        findViewById(R.id.btn_sina).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
            //WBAuthActivity即為授權界面的Activity Intent i
= new Intent(MainActivity.this, WBAuthActivity.class); startActivity(i); } }); } }

 

獲取微博返回的Token信息后,獲取微博內容的操作:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;

import com.sina.weibo.sdk.auth.AuthInfo;
import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.auth.WeiboAuthListener;
import com.sina.weibo.sdk.auth.sso.SsoHandler;
import com.sina.weibo.sdk.exception.WeiboException;

import java.text.SimpleDateFormat;


public class WBAuthActivity extends Activity {
    
    private static final String TAG = "MyApplication";

    /** 顯示認證后的信息,如 AccessToken */
    private TextView mTokenText;

    private AuthInfo mAuthInfo;

    /** 封裝了 "access_token","expires_in","refresh_token",並提供了他們的管理功能  */
    private Oauth2AccessToken mAccessToken;

    /** 注意:SsoHandler 僅當 SDK 支持 SSO 時有效 */
    private SsoHandler mSsoHandler;

    /**
     * @see {@link Activity#onCreate}
     */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_auth);

// 創建微博實例
        //mWeiboAuth = new WeiboAuth(this, Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE);
        // 快速授權時,請不要傳入 SCOPE,否則可能會授權不成功
        mAuthInfo = new AuthInfo(this, Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE);
        mSsoHandler = new SsoHandler(WBAuthActivity.this, mAuthInfo);
        mTokenText = (TextView) findViewById(R.id.mTokenText);


        // SSO 授權, ALL IN ONE   如果手機安裝了微博客戶端則使用客戶端授權,沒有則進行網頁授權
        findViewById(R.id.obtain_token_via_allInOne).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                mSsoHandler.authorize(new AuthListener());
            }
        });

        //獲取微博信息,這里是已經獲得授權信息后,進行獲取微博返回的操作切入點
        findViewById(R.id.btn_sinaWeiBo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                Intent i = new Intent(WBAuthActivity.this,WeiboManager.class);
                startActivity(i);
            }
        });

        // 用戶登出,即銷毀已獲得的Token信息
        findViewById(R.id.logout).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                AccessTokenKeeper.clear(getApplicationContext());
                mAccessToken = new Oauth2AccessToken();
                updateTokenView(false);
            }
        });// 從 SharedPreferences 中讀取上次已保存好 AccessToken 等信息,
        // 第一次啟動本應用,AccessToken 不可用
        mAccessToken = AccessTokenKeeper.readAccessToken(this);
        if (mAccessToken.isSessionValid()) {
            updateTokenView(true);
        }
    }

    /**
     * 當 SSO 授權 Activity 退出時,該函數被調用。
     *
     * @see {@link Activity#onActivityResult}
     */
  //此方法必須寫上,原因由於時間太長,已然忘記,只記得必須寫 - -!!!! @Override protected void onActivityResult(int requestCode, int resultCode, Intent data) { super.onActivityResult(requestCode, resultCode, data); // SSO 授權回調 // 重要:發起 SSO 登陸的 Activity 必須重寫 onActivityResults if (mSsoHandler != null) { mSsoHandler.authorizeCallBack(requestCode, resultCode, data); } } /** * 微博認證授權回調類。 * 1. SSO 授權時,需要在 {@link #onActivityResult} 中調用 {@link SsoHandler#authorizeCallBack} 后, * 該回調才會被執行。 * 2. 非 SSO 授權時,當授權結束后,該回調就會被執行。 * 當授權成功后,請保存該 access_token、expires_in、uid 等信息到 SharedPreferences 中。 */ class AuthListener implements WeiboAuthListener { @Override public void onComplete(Bundle values) { // 從 Bundle 中解析 Token mAccessToken = Oauth2AccessToken.parseAccessToken(values); //從這里獲取用戶輸入的 電話號碼信息 String phoneNum = mAccessToken.getPhoneNum(); if (mAccessToken.isSessionValid()) { // 顯示 Token updateTokenView(false); // 保存 Token 到 SharedPreferences AccessTokenKeeper.writeAccessToken(WBAuthActivity.this, mAccessToken); Toast.makeText(WBAuthActivity.this, "保存Accesstoken成功", Toast.LENGTH_SHORT).show(); } else { // 以下幾種情況,您會收到 Code: // 1. 當您未在平台上注冊的應用程序的包名與簽名時; // 2. 當您注冊的應用程序包名與簽名不正確時; // 3. 當您在平台上注冊的包名和簽名與您當前測試的應用的包名和簽名不匹配時。 String code = values.getString("code"); String message = "get token failed"; if (!TextUtils.isEmpty(code)) { message = message + "\nObtained the code: " + code; } Toast.makeText(WBAuthActivity.this, message, Toast.LENGTH_LONG).show(); } } @Override public void onCancel() { Toast.makeText(WBAuthActivity.this, "取消", Toast.LENGTH_LONG).show(); } @Override public void onWeiboException(WeiboException e) { Toast.makeText(WBAuthActivity.this, "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG).show(); } } /** * 顯示當前 Token 信息。 * * @param hasExisted 配置文件中是否已存在 token 信息並且合法 */ private void updateTokenView(boolean hasExisted) { String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format( new java.util.Date(mAccessToken.getExpiresTime())); String format = getString(R.string.weibosdk_demo_token_to_string_format_1); mTokenText.setText(String.format(format, mAccessToken.getToken(), date)); String message = String.format(format, mAccessToken.getToken(), date); if (hasExisted) { message = getString(R.string.weibosdk_demo_token_has_existed) + "\n" + message; } mTokenText.setText(message); } }

//注:以上很多東西均來自SDK Demo的示例代碼,為了適應自己的工程稍作修改所以保留了絕大部分不需要改動的部分


已經通過了Token驗證,並連接到weibo后,進入自己編寫的管理窗口Activity:

具體代碼:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.text.TextUtils;
import android.view.View;
import android.widget.Toast;

import com.sina.weibo.sdk.auth.Oauth2AccessToken;
import com.sina.weibo.sdk.exception.WeiboException;
import com.sina.weibo.sdk.net.RequestListener;
import com.sina.weibo.sdk.openapi.UsersAPI;
import com.sina.weibo.sdk.openapi.legacy.StatusesAPI;

public class WeiboManager extends Activity {
    private Oauth2AccessToken mAccessToken;
    private UsersAPI mUsersAPI;
    private StatusesAPI statusesAPI;


//    private IWeiboShareAPI mWeiboShareAPI;

    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_weibo_manager);

//        mWeiboShareAPI = WeiboShareSDK.createWeiboAPI(this,Constants.APP_KEY);
//        mWeiboShareAPI.registerApp();

        // 獲取當前已保存過的 Token
        mAccessToken = AccessTokenKeeper.readAccessToken(this);
        mUsersAPI = new UsersAPI(WeiboManager.this,Constants.APP_KEY,mAccessToken); // 獲取用戶信息接口
        statusesAPI = new StatusesAPI(WeiboManager.this,Constants.APP_KEY,mAccessToken); //創建微博分享接口實例

        findViewById(R.id.btn_StartWeibo).setOnClickListener(new View.OnClickListener() {
            @Override
            public void onClick(View v) {
                //這是獲取綁定微博的最新微博信息的靜態方法
          //下面各自的參數有着不同的代表意義,在API的源代碼文檔中有詳細的說明,其中第三個參數30代表的是返回30條該用戶的最新微博信息
          //需要注意的是最后需要傳入RequestListener對象,此對象會收到服務器的返回信息
          statusesAPI.friendsTimeline(
0,0,30,1,false,0,false,mListener); } }); }    //新建一個RequestListener對象,此對象用來接收微博服務器給出的回應消息
   // 對於返回值的具體操作由自己編寫
private RequestListener mListener = new RequestListener() { @Override public void onComplete(String response) { if (!TextUtils.isEmpty(response)) {

        //這里的response即為微博服務器返回的信息流,格式為json
        //將此信息流通過Intent傳遞到對應的顯示Activity中,再行解析和顯示
Intent i
= new Intent(WeiboManager.this, WeiboListView.class); i.putExtra("response", response); startActivity(i); } } @Override public void onWeiboException (WeiboException e){ Toast.makeText(WeiboManager.this, "WeiboException", Toast.LENGTH_LONG).show(); } }; }

通過Intent對象傳遞的response數據的對應Activity對應的代碼:

import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.os.Handler;
import android.os.Message;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.ListView;

import com.sina.weibo.sdk.openapi.models.User;

import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

import java.util.ArrayList;

public class WeiboListView extends Activity{

    private ListView WeiboListView;
    private ArrayList<CustomWeibo> CustomWeibos;
    private String response;
    private CustomWeibo customWeibo;
    private Handler handler = null;
    private ListAdapter adapter;


    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_weibo_list_view);

        WeiboListView = (ListView) findViewById(R.id.WeiboListView);
        CustomWeibos = new ArrayList<CustomWeibo>();

    //獲取微博返回的數據流對象(注:通過Intent傳遞信息的數據量有限制,使用需慎重!)
        Intent i = getIntent();
        response = i.getStringExtra("response");

        // 將獲得的response信息傳遞到自己編寫的方法中,解析JSON數據流的信息內容
        parsingJSON(response);

     //以下的異步方法是為了實現對於圖片的異步加載 Runnable runnable = new Runnable() { @Override public void run() { try {
             //一定要線程休眠一段時間,因為新建handler在下一步,若不休眠會產生空指針異常 Thread.sleep(
2000);
             //休眠2s后,當解析完成了,將解析后的微博數據傳遞給handler更新UI handler.sendMessage(handler.obtainMessage(
0,CustomWeibos)); } catch (InterruptedException e) { e.printStackTrace(); } } }; new Thread(runnable).start(); handler = new Handler(){ @Override public void handleMessage(Message msg) { if (msg.what == 0){
            //但接收的消息是來自上面的代碼發送,則啟動程序,更新UI
            //(但有一點表示懷疑,數據解析的速度和上文中執行代碼的速度是否能夠保證數據的完整和線程安全) //CustomWeibo是自己為了更方便地顯示微博信息而自定義的類,里面包含了一條微博所要顯示的內容,通過ArrayList來保存
            ArrayList
<CustomWeibo> CustomeWeibos = (ArrayList<CustomWeibo>) msg.obj; //這是為了保證數據在每個控件正確顯示而寫出來的調用函數
            BinderListData(CustomeWeibos); } } };
}    //解析JSon數據內容不做解釋,簡單易懂,相信自己不會以后再來看不懂 public void parsingJSON(String response){ try { JSONObject jsonObject = new JSONObject(response); JSONArray array = jsonObject.getJSONArray("statuses"); JSONObject temp = null; String text = null; int count = -1; JSONObject usertemp = null; User user = null; for (int i = 0;i<array.length();i++){ customWeibo = new CustomWeibo(); if ((temp=array.getJSONObject(i))!=null){ //微博正文 if ((text = temp.getString("text"))!=null){ customWeibo.setText(text); } //發布時間 if ((text = temp.getString("created_at"))!=null){ customWeibo.setCreated_at(text); } //用戶信息 if ((usertemp = temp.getJSONObject("user"))!=null){ user = User.parse(usertemp); customWeibo.setUser(user); user=null; } //轉發數 if ((count = temp.getInt("reposts_count"))!=-1){ customWeibo.setReports_count(count); count = -1; } //評論數 if ((count = temp.getInt("comments_count"))!=-1){ customWeibo.setComment_count(count); count = -1; } //點贊數 if ((count = temp.getInt("attitudes_count"))!=-1){ customWeibo.setAttitudes_count(count); count = -1; } CustomWeibos.add(customWeibo); customWeibo = null; } } } catch (JSONException e) { e.printStackTrace(); } } public void BinderListData(final ArrayList<CustomWeibo> CustomeWeibos){
    //由下可以明顯看出我們還自定義了一個用於顯示微博信息的適配器內容的adapter,下文貼出 adapter
= new ListViewAdapter(R.layout.item,WeiboListView.this,CustomeWeibos); WeiboListView.setAdapter(adapter); } private void LoadImage(ImageView imageView,String path){
    //為了實現圖片異步加載和顯示,自定義了一個異步加載圖片並顯示的類,下文貼出 AsyncTaskImageLoad asyncTaskImageLoad
= new AsyncTaskImageLoad(imageView); asyncTaskImageLoad.execute(path); } }

 

這是用於顯示微博信息的界面適配器的具體代碼:

import android.app.Activity;
import android.content.Context;
import android.view.LayoutInflater;
import android.view.View;
import android.view.ViewGroup;
import android.widget.BaseAdapter;
import android.widget.Button;
import android.widget.ImageView;
import android.widget.ListAdapter;
import android.widget.TextView;

import java.util.ArrayList;

/**
 * Created by Andrew on 2016/7/21.
 */
public class ListViewAdapter extends BaseAdapter implements ListAdapter {
    private ArrayList<CustomWeibo> CustomWeibos;
    private int id;
    private Context context;
    private LayoutInflater inflater;

    public ListViewAdapter(int item, Activity mainActivity, ArrayList<CustomWeibo> data){
        this.context = mainActivity;
        this.id = item;
        inflater = LayoutInflater.from(context);
        this.CustomWeibos = data;
    }


    @Override
    public int getCount() {
        return CustomWeibos.size();
    }

    @Override
    public Object getItem(int position) {
        return CustomWeibos.get(position);
    }

    @Override
    public long getItemId(int position) {
        return position;
    }

    @Override
    public View getView(int position, View convertView, ViewGroup parent) {
        ImageView img = null;
        ImageView iv_sina_head = null;
        TextView tv_UserName = null;
        TextView tv_sinaWeibo = null;
        Button reports_count = null;
        Button comment_count = null;
        Button attitudes_count = null;
        if (convertView == null){
            convertView = inflater.inflate(id,null);
            iv_sina_head = (ImageView) convertView.findViewById(R.id.iv_sina_head);
            tv_UserName = (TextView) convertView.findViewById(R.id.tv_UserName);
            tv_sinaWeibo = (TextView) convertView.findViewById(R.id.tv_sinaWeibo);
            reports_count = (Button) convertView.findViewById(R.id.reports_count);
            comment_count = (Button) convertView.findViewById(R.id.comment_count);
            attitudes_count = (Button) convertView.findViewById(R.id.attitudes_count);

        //整段代碼最重要的部分就是這一句!//整段代碼最重要的部分就是這一句!//整段代碼最重要的部分就是這一句!//整段代碼最重要的部分就是這一句!
convertView.setTag(
new ObjectClass(iv_sina_head,tv_UserName,tv_sinaWeibo,reports_count,comment_count,attitudes_count));

//另外需要提醒自己的是,這段程序不是僅僅執行一次,而是每一次對界面的滑動和操作都會調用此方法,故自定義了一個對象,用於綁定對應的控件內容,保證正確顯示

}
else { ObjectClass objectClass = (ObjectClass) convertView.getTag(); iv_sina_head = objectClass.iv_sina_head; tv_UserName = objectClass.tv_UserName; tv_sinaWeibo = objectClass.tv_sinaWeibo; reports_count = objectClass.reports_count; comment_count = objectClass.comment_count; attitudes_count = objectClass.attitudes_count; } tv_sinaWeibo.setText(CustomWeibos.get(position).getText()); reports_count.setText("轉發數:"+CustomWeibos.get(position).getReports_count()); comment_count.setText("評論數:"+CustomWeibos.get(position).getComment_count()); attitudes_count.setText("點贊數:"+CustomWeibos.get(position).getAttitudes_count()); tv_UserName.setText(CustomWeibos.get(position).getUser().name); String Url = CustomWeibos.get(position).getUser().profile_image_url; LoadImage(iv_sina_head,Url); return convertView; } private void LoadImage(ImageView imageView,String path){ AsyncTaskImageLoad asyncTaskImageLoad = new AsyncTaskImageLoad(imageView); asyncTaskImageLoad.execute(path); } private final class ObjectClass{ ImageView iv_sina_head = null; TextView tv_UserName = null; TextView tv_sinaWeibo = null; Button reports_count = null; Button comment_count = null; Button attitudes_count = null; public ObjectClass(ImageView iv_sina_head,TextView tv_UserName,TextView tv_sinaWeibo,Button reports_count,Button comment_count,Button attitudes_count){ this.attitudes_count = attitudes_count; this.comment_count = comment_count; this.iv_sina_head = iv_sina_head; this.reports_count = reports_count; this.tv_sinaWeibo = tv_sinaWeibo; this.tv_UserName = tv_UserName; } } }


下面是一部加載圖片的方法:

import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.os.AsyncTask;
import android.widget.ImageView;

import java.io.IOException;
import java.io.InputStream;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;

/**
 * Created by Andrew on 2016/7/21.
 */
public class AsyncTaskImageLoad extends AsyncTask<String,Integer,Bitmap> {

    private ImageView image = null;

    public AsyncTaskImageLoad(ImageView imageView){
        this.image = imageView;
    }


    @Override
    protected Bitmap doInBackground(String... params) {
        try {
            URL Url = new URL(params[0]);
            HttpURLConnection connection = (HttpURLConnection) Url.openConnection();
            connection.setRequestMethod("POST");
            connection.setConnectTimeout(5000);
            if (connection.getResponseCode() == 200){
                InputStream inputStream = connection.getInputStream();
                Bitmap map = BitmapFactory.decodeStream(inputStream);
                return map;
            }
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return null;
    }

    @Override
    protected void onPostExecute(Bitmap bitmap) {
        if (image!=null&&bitmap!=null){
            image.setImageBitmap(bitmap);
        }
    }
}

 

 

最后對於看到本段代碼的說明:

作為一個菜鳥,這里寫的代碼多半是為了寫給自己看

這里僅僅實現了微博信息的獲取和顯示,圖片異步加載功能,有很多功能並沒有實現,其中有很多方法有嚴重的性能問題,但為了先行實現功能而未作修改

若是對於本文代碼有任何問題,歡迎留言聯系或直接詢問,不吝指點,共同提高。

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM