需求
手頭的一個應用需要添加分享到新浪微博的功能,這個功能在現在的應用上是非常的普遍的了。
分享到新浪微博,其實就是發送一條特定內容的微博,所以需要用到新浪微博SDK了。
微博SDK
SDK的下載地址 http://open.weibo.com/wiki/SDK,包括很多平台的封裝,其中就有android版本的。
下載后,請務必讀一下SDK文檔,運行其中自帶的demo,對sdk的使用有個大概的了解。
發送微博的困擾
運行DEMO后發現,其中發送微博的功能竟然是通過調用微博客戶端的方式來實現的,如果用戶沒有安裝,會提示用戶下載,或者選擇放棄發送。。。這明顯不靠譜啊,因為還是有很多用戶沒有安裝微博客戶端的。
網上也有不少人遇到這個問題,從他們的說法中可以看出微博sdk前一個版本中似乎還是有發送微博這個功能的,不過新版的sdk中沒有了。
不過demo中還是給了提示了:如果不想使用微博客戶端進行分享,請參考OpenAPI。
那我們就來看看這OpenAPI有什么功能。
OpenAPI
OpenAPI的文檔:http://open.weibo.com/wiki/%E5%BE%AE%E5%8D%9AAPI
可以看出OpenAPI就是通過Http請求的方式來進行一些操作,可以進行的操作基本涵蓋了微博應用的所有方面。
我們找到發送微博的API:statuses/update
文檔的說明很詳細,改接口通過POST方法,請求參數有很多,不過必須的只有一個。不過,改接口是需要登錄的,所以參數中還需加上登錄授權過的AccessToken:
參數名 | 必選 | 類型及范圍 | 說明 |
---|---|---|---|
status | true | string | 要發布的微博文本內容,必須做URLencode,內容不超過140個漢字。 |
access_token | true | string | 登錄后得到,詳見后文 |
現在,發送微博的邏輯很明確了,就是一個post請求。還需要解決的一個問題就是AccessToken,即登錄授權。
登錄授權
並不是你想讓用戶在你的應用里登錄微博就可以直接寫代碼實現的,因為用戶是在你的應用里輸入賬戶信息,所以對於用戶的賬戶安全來說,這是有風險的,所以如果你的應用需要加入微博功能,是需通過新浪審核的。這個流程我也沒有完整的走過,不過大家可以參考微博文檔的幫助:移動客戶端接入
這篇文章主要講程序,所以不在這些流程上糾結。總之,我們需要的是一個APPKEY,登錄授權需要它。我們現在可以先用SDK微博應用demo的APPKEY來實驗。
DEMO實踐步驟
- 因為使用的是微博DEMO的APPKEY所以需要替換默認的 debug.keystore
在 C:\Users\XXXXX.android 目錄下,把 Android 默認的 debug.keystore 替換成官方在 GitHub 上提供的debug.keystore。
請注意:這一步是必須的,如果沒有替換,demo 程序在運行時將無法正確的授權成功。用戶在替換前,最好先備份一下原始的 debug.keystore。另外,該 debug.keysotre 是新浪官方的,除了編譯運行官方 DEMO 外,請不要直接使用它,出於安全的考慮,您應該為自己的應用提供一份 keysotre。 - 新建android工程,包名取名為:com.sina.weibo.sdk.demo
- 拷貝微博DEMO中的Constants.java到工程中
-
在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_EXTERNAL_STORAGE" />
-
主界面的代碼,登錄授權部分的代碼直接取自微博官方DEMO,發送微博部分是上文分析的實現:
public class MainActivity extends Activity { private static final String TAG = "MainActivity"; /** 微博 Web 授權類,提供登陸等功能 */ private WeiboAuth mWeiboAuth; /** 封裝了 "access_token","expires_in","refresh_token",並提供了他們的管理功能 */ private Oauth2AccessToken mAccessToken; private TextView mTokenInfoTV; private EditText mMessageET; private Button mSendBtn; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); mWeiboAuth = new WeiboAuth(this, Constants.APP_KEY, Constants.REDIRECT_URL, Constants.SCOPE); mTokenInfoTV = (TextView) findViewById(R.id.textView_tokenInfo); mMessageET = (EditText) findViewById(R.id.editText_message); mSendBtn = (Button) findViewById(R.id.button_sendWeibo); // 獲取Token findViewById(R.id.button_getToken).setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { mWeiboAuth.anthorize(new AuthListener()); } }); // 發送微博 mMessageET.setVisibility(View.GONE); mSendBtn.setVisibility(View.GONE); mSendBtn.setOnClickListener(new View.OnClickListener() { @Override public void onClick(View v) { sendWeibo(mMessageET.getText().toString()); } }); } // 發送微博 protected void sendWeibo(String string) { //組織post參數 List<BasicNameValuePair> params = new LinkedList<BasicNameValuePair>(); params.add(new BasicNameValuePair("status", string)); params.add(new BasicNameValuePair("access_token", mAccessToken.getToken())); HttpClient httpClient = new DefaultHttpClient(); //傳入post方法的請求地址,即發送微博的api接口 HttpPost postMethod = new HttpPost("https://api.weibo.com/2/statuses/update.json"); try { postMethod.setEntity(new UrlEncodedFormEntity(params, "utf-8")); HttpResponse httpResponse = httpClient.execute(postMethod); //將返回結果轉為字符串,通過文檔可知返回結果為json字符串,結構請參考文檔 String resultStr=EntityUtils.toString(httpResponse.getEntity()); Log.e(TAG, resultStr); //從json字符串中建立JSONObject JSONObject resultJson = new JSONObject(resultStr); //如果發送微博失敗的話,返回字段中有"error"字段,通過判斷是否存在該字段即可知道是否發送成功 if (resultJson.has("error")) { Toast.makeText(this, "發送失敗", Toast.LENGTH_SHORT).show(); } else { Toast.makeText(this, "發送成功", Toast.LENGTH_SHORT).show(); } } catch (UnsupportedEncodingException e) { Log.e(TAG, e.getLocalizedMessage()); } catch (ClientProtocolException e) { Log.e(TAG, e.getLocalizedMessage()); } catch (IOException e) { Log.e(TAG, e.getLocalizedMessage()); } catch (ParseException e) { Log.e(TAG, e.getLocalizedMessage()); } catch (JSONException e) { Log.e(TAG, e.getLocalizedMessage()); } } //登錄授權接口 class AuthListener implements WeiboAuthListener { //登錄成功 @Override public void onComplete(Bundle values) { // 從 Bundle 中解析 Token mAccessToken = Oauth2AccessToken.parseAccessToken(values); if (mAccessToken.isSessionValid()) { // 顯示 Token updateTokenView(); // 顯示發送微博的按鈕和輸入框 mSendBtn.setVisibility(View.VISIBLE); mMessageET.setVisibility(View.VISIBLE); // 保存 Token 到 SharedPreferences // AccessTokenKeeper.writeAccessToken(MainActivity.this, // mAccessToken); Toast.makeText(MainActivity.this, "授權成功", Toast.LENGTH_SHORT).show(); } else { // 當您注冊的應用程序簽名不正確時,就會收到 Code,請確保簽名正確 String code = values.getString("code"); String message = "授權失敗"; if (!TextUtils.isEmpty(code)) { message = message + "\nObtained the code: " + code; } Toast.makeText(MainActivity.this, message, Toast.LENGTH_LONG).show(); } } @Override public void onCancel() { Toast.makeText(MainActivity.this, "取消授權", Toast.LENGTH_LONG).show(); } @Override public void onWeiboException(WeiboException e) { Toast.makeText(MainActivity.this, "Auth exception : " + e.getMessage(), Toast.LENGTH_LONG).show(); } } //顯示token信息 private void updateTokenView() { String date = new SimpleDateFormat("yyyy/MM/dd HH:mm:ss").format(new java.util.Date(mAccessToken .getExpiresTime())); String format = "Token:%1$s \n有效期:%2$s"; mTokenInfoTV.setText(String.format(format, mAccessToken.getToken(), date)); } @Override public boolean onCreateOptionsMenu(Menu menu) { // Inflate the menu; this adds items to the action bar if it is present. getMenuInflater().inflate(R.menu.main, menu); return true; } }
-
主界面的布局代碼:
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/LinearLayout1" android:layout_width="match_parent" android:layout_height="match_parent" android:orientation="vertical" tools:context=".MainActivity" > <Button android:id="@+id/button_getToken" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="獲取token" /> <TextView android:layout_width="wrap_content" android:layout_height="wrap_content" android:text="Token 信息:" android:textSize="20sp" /> <TextView android:id="@+id/textView_tokenInfo" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="" android:textSize="20sp" /> <EditText android:id="@+id/editText_message" android:layout_width="match_parent" android:layout_height="wrap_content" android:ems="10" > <requestFocus /> </EditText> <Button android:id="@+id/button_sendWeibo" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="發送微博" /> </LinearLayout>