项目需要,在此记录,以便查阅。
1. 进入http://open.qq.com/,登录,然后点击右上角的管理中心,进入创建应用界面,但如果你是第一次登录,会要求你填写资料,传个身份证审核一下,一般隔天就可以创建了。
填写应用名称
创建成功
重要的appid拿到了,当然你也可以使用别人的appid,但是显示的就是别人应用的信息了。
二 QQ登录
http://wiki.connect.qq.com/这是QQ的api文档,相关的jar包可以在上面下载,api上面也介绍的比较详细。本文后的demo已经有所需要的jar包,不需重复下载。
相关代码如下:
BaseUIListener.java
package com.eeb.qqauthdemo;
import org.json.JSONObject;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.UiError;
import android.app.Activity;
import android.content.Context;
import android.os.Handler;
import android.os.Message;
public class BaseUIListener implements IUiListener {
private Context mContext;
private String mScope;
private boolean mIsCaneled;
private static final int ON_COMPLETE = 0;
private static final int ON_ERROR = 1;
private static final int ON_CANCEL = 2;
private Handler mHandler = new Handler() {
@Override
public void handleMessage(Message msg) {
switch (msg.what) {
case ON_COMPLETE:
JSONObject response = (JSONObject)msg.obj;
Util.showResultDialog(mContext, response.toString(), "onComplete");
Util.dismissDialog();
break;
case ON_ERROR:
UiError e = (UiError)msg.obj;
Util.showResultDialog(mContext, "errorMsg:" + e.errorMessage
+ "errorDetail:" + e.errorDetail, "onError");
Util.dismissDialog();
break;
case ON_CANCEL:
Util.toastMessage((Activity)mContext, "onCancel");
break;
}
}
};
public BaseUIListener(Context mContext) {
super();
this.mContext = mContext;
}
public BaseUIListener(Context mContext, String mScope) {
super();
this.mContext = mContext;
this.mScope = mScope;
}
public void cancel() {
mIsCaneled = true;
}
@Override
public void onComplete(Object response) {
if (mIsCaneled) return;
Message msg = mHandler.obtainMessage();
msg.what = ON_COMPLETE;
msg.obj = response;
mHandler.sendMessage(msg);
}
@Override
public void onError(UiError e) {
if (mIsCaneled) return;
Message msg = mHandler.obtainMessage();
msg.what = ON_ERROR;
msg.obj = e;
mHandler.sendMessage(msg);
}
@Override
public void onCancel() {
if (mIsCaneled) return;
Message msg = mHandler.obtainMessage();
msg.what = ON_CANCEL;
mHandler.sendMessage(msg);
}
public Context getmContext() {
return mContext;
}
public void setmContext(Context mContext) {
this.mContext = mContext;
}
}
package com.eeb.qqauthdemo;
import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.RandomAccessFile;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.net.URLConnection;
import junit.framework.Assert;
import android.app.Activity;
import android.app.AlertDialog;
import android.app.Dialog;
import android.app.ProgressDialog;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.Bitmap.CompressFormat;
import android.graphics.BitmapFactory;
import android.text.TextUtils;
import android.util.Log;
import android.widget.Toast;
public class Util {
private static final String TAG = "SDK_Sample.Util";
private static Dialog mProgressDialog;
private static Toast mToast;
/* Convert byte[] to hex string.这里我们可以将byte转换成int,然后利用Integer.toHexString(int)来转换成16进制字符串。
* @param src byte[] data
* @return hex string
*/
public static String bytesToHexString(byte[] src){
StringBuilder stringBuilder = new StringBuilder("");
if (src == null || src.length <= 0) {
return null;
}
for (int i = 0; i < src.length; i++) {
int v = src[i] & 0xFF;
String hv = Integer.toHexString(v);
if (hv.length() < 2) {
stringBuilder.append(0);
}
stringBuilder.append(hv);
}
return stringBuilder.toString();
}
/**
* Convert hex string to byte[]
* @param hexString the hex string
* @return byte[]
*/
public static byte[] hexStringToBytes(String hexString) {
if (hexString == null || hexString.equals("")) {
return null;
}
hexString = hexString.toUpperCase();
int length = hexString.length() / 2;
char[] hexChars = hexString.toCharArray();
byte[] d = new byte[length];
for (int i = 0; i < length; i++) {
int pos = i * 2;
d[i] = (byte) (charToByte(hexChars[pos]) << 4 | charToByte(hexChars[pos + 1]));
}
return d;
}
/**
* Convert char to byte
* @param c char
* @return byte
*/
private static byte charToByte(char c) {
return (byte) "0123456789ABCDEF".indexOf(c);
}
/*
* 16进制数字字符集
*/
private static String hexString="0123456789ABCDEF";
/*
* 将字符串编码成16进制数字,适用于所有字符(包括中文)
*/
public static String toHexString(String str)
{
//根据默认编码获取字节数组
byte[] bytes=str.getBytes();
StringBuilder sb=new StringBuilder(bytes.length*2);
//将字节数组中每个字节拆解成2位16进制整数
for(int i=0;i<bytes.length;i++)
{
sb.append(hexString.charAt((bytes[i]&0xf0)>>4));
sb.append(hexString.charAt((bytes[i]&0x0f)>>0));
}
return sb.toString();
}
//转换十六进制编码为字符串
public static String hexToString(String s)
{
if("0x".equals(s.substring(0, 2)))
{
s =s.substring(2);
}
byte[] baKeyword = new byte[s.length()/2];
for(int i = 0; i < baKeyword.length; i++)
{
try
{
baKeyword[i] = (byte)(0xff & Integer.parseInt(s.substring(i*2, i*2+2),16));
}
catch(Exception e)
{
e.printStackTrace();
}
}
try
{
s = new String(baKeyword, "utf-8");//UTF-16le:Not
}
catch (Exception e1)
{
e1.printStackTrace();
}
return s;
}
public static byte[] bmpToByteArray(final Bitmap bmp, final boolean needRecycle) {
ByteArrayOutputStream output = new ByteArrayOutputStream();
bmp.compress(CompressFormat.PNG, 100, output);
if (needRecycle) {
bmp.recycle();
}
byte[] result = output.toByteArray();
try {
output.close();
} catch (Exception e) {
e.printStackTrace();
}
return result;
}
public static byte[] getHtmlByteArray(final String url) {
URL htmlUrl = null;
InputStream inStream = null;
try {
htmlUrl = new URL(url);
URLConnection connection = htmlUrl.openConnection();
HttpURLConnection httpConnection = (HttpURLConnection)connection;
int responseCode = httpConnection.getResponseCode();
if(responseCode == HttpURLConnection.HTTP_OK){
inStream = httpConnection.getInputStream();
}
} catch (MalformedURLException e) {
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
byte[] data = inputStreamToByte(inStream);
return data;
}
public static byte[] inputStreamToByte(InputStream is) {
try{
ByteArrayOutputStream bytestream = new ByteArrayOutputStream();
int ch;
while ((ch = is.read()) != -1) {
bytestream.write(ch);
}
byte imgdata[] = bytestream.toByteArray();
bytestream.close();
return imgdata;
}catch(Exception e){
e.printStackTrace();
}
return null;
}
public static byte[] readFromFile(String fileName, int offset, int len) {
if (fileName == null) {
return null;
}
File file = new File(fileName);
if (!file.exists()) {
Log.i(TAG, "readFromFile: file not found");
return null;
}
if (len == -1) {
len = (int) file.length();
}
Log.d(TAG, "readFromFile : offset = " + offset + " len = " + len + " offset + len = " + (offset + len));
if(offset <0){
Log.e(TAG, "readFromFile invalid offset:" + offset);
return null;
}
if(len <=0 ){
Log.e(TAG, "readFromFile invalid len:" + len);
return null;
}
if(offset + len > (int) file.length()){
Log.e(TAG, "readFromFile invalid file len:" + file.length());
return null;
}
byte[] b = null;
try {
RandomAccessFile in = new RandomAccessFile(fileName, "r");
b = new byte[len];
in.seek(offset);
in.readFully(b);
in.close();
} catch (Exception e) {
Log.e(TAG, "readFromFile : errMsg = " + e.getMessage());
e.printStackTrace();
}
return b;
}
public static int computeSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
int initialSize = computeInitialSampleSize(options, minSideLength,
maxNumOfPixels);
int roundedSize;
if (initialSize <= 8) {
roundedSize = 1;
while (roundedSize < initialSize) {
roundedSize <<= 1;
}
} else {
roundedSize = (initialSize + 7) / 8 * 8;
}
return roundedSize;
}
private static int computeInitialSampleSize(BitmapFactory.Options options,
int minSideLength, int maxNumOfPixels) {
double w = options.outWidth;
double h = options.outHeight;
int lowerBound = (maxNumOfPixels == -1) ? 1 :
(int) Math.ceil(Math.sqrt(w * h / maxNumOfPixels));
int upperBound = (minSideLength == -1) ? 128 :
(int) Math.min(Math.floor(w / minSideLength),
Math.floor(h / minSideLength));
if (upperBound < lowerBound) {
// return the larger one when there is no overlapping zone.
return lowerBound;
}
if ((maxNumOfPixels == -1) &&
(minSideLength == -1)) {
return 1;
} else if (minSideLength == -1) {
return lowerBound;
} else {
return upperBound;
}
}
/**
* 以最省内存的方式读取图片
*/
public static Bitmap readBitmap(final String path){
try{
FileInputStream stream = new FileInputStream(new File(path+"test.jpg"));
BitmapFactory.Options opts = new BitmapFactory.Options();
opts.inSampleSize = 8;
opts.inPurgeable=true;
opts.inInputShareable=true;
Bitmap bitmap = BitmapFactory.decodeStream(stream , null, opts);
return bitmap;
}
catch (Exception e){
return null;
}
}
private static final int MAX_DECODE_PICTURE_SIZE = 1920 * 1440;
public static Bitmap extractThumbNail(final String path, final int height, final int width, final boolean crop) {
Assert.assertTrue(path != null && !path.equals("") && height > 0 && width > 0);
BitmapFactory.Options options = new BitmapFactory.Options();
try {
options.inJustDecodeBounds = true;
Bitmap tmp = BitmapFactory.decodeFile(path, options);
if (tmp != null) {
tmp.recycle();
tmp = null;
}
Log.d(TAG, "extractThumbNail: round=" + width + "x" + height + ", crop=" + crop);
final double beY = options.outHeight * 1.0 / height;
final double beX = options.outWidth * 1.0 / width;
Log.d(TAG, "extractThumbNail: extract beX = " + beX + ", beY = " + beY);
options.inSampleSize = (int) (crop ? (beY > beX ? beX : beY) : (beY < beX ? beX : beY));
if (options.inSampleSize <= 1) {
options.inSampleSize = 1;
}
// NOTE: out of memory error
while (options.outHeight * options.outWidth / options.inSampleSize > MAX_DECODE_PICTURE_SIZE) {
options.inSampleSize++;
}
int newHeight = height;
int newWidth = width;
if (crop) {
if (beY > beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
} else {
if (beY < beX) {
newHeight = (int) (newWidth * 1.0 * options.outHeight / options.outWidth);
} else {
newWidth = (int) (newHeight * 1.0 * options.outWidth / options.outHeight);
}
}
options.inJustDecodeBounds = false;
Log.i(TAG, "bitmap required size=" + newWidth + "x" + newHeight + ", orig=" + options.outWidth + "x" + options.outHeight + ", sample=" + options.inSampleSize);
Bitmap bm = BitmapFactory.decodeFile(path, options);
if (bm == null) {
Log.e(TAG, "bitmap decode failed");
return null;
}
Log.i(TAG, "bitmap decoded size=" + bm.getWidth() + "x" + bm.getHeight());
final Bitmap scale = Bitmap.createScaledBitmap(bm, newWidth, newHeight, true);
if (scale != null) {
bm.recycle();
bm = scale;
}
if (crop) {
final Bitmap cropped = Bitmap.createBitmap(bm, (bm.getWidth() - width) >> 1, (bm.getHeight() - height) >> 1, width, height);
if (cropped == null) {
return bm;
}
bm.recycle();
bm = cropped;
Log.i(TAG, "bitmap croped size=" + bm.getWidth() + "x" + bm.getHeight());
}
return bm;
} catch (final OutOfMemoryError e) {
Log.e(TAG, "decode bitmap failed: " + e.getMessage());
options = null;
}
return null;
}
public static final void showResultDialog(Context context, String msg,
String title) {
if(msg == null) return;
String rmsg = msg.replace(",", "\n");
Log.d("Util", rmsg);
new AlertDialog.Builder(context).setTitle(title).setMessage(rmsg)
.setNegativeButton("知道了", null).create().show();
}
public static final void showProgressDialog(Context context, String title,
String message) {
dismissDialog();
if (TextUtils.isEmpty(title)) {
title = "请稍候";
}
if (TextUtils.isEmpty(message)) {
message = "正在加载...";
}
mProgressDialog = ProgressDialog.show(context, title, message);
}
public static final void dismissDialog() {
if (mProgressDialog != null) {
mProgressDialog.dismiss();
mProgressDialog = null;
}
}
/**
* 打印消息并且用Toast显示消息
*
* @param activity
* @param message
* @param logLevel
* 填d, w, e分别代表debug, warn, error; 默认是debug
*/
public static final void toastMessage(final Activity activity,
final String message, String logLevel) {
if ("w".equals(logLevel)) {
Log.w("sdkDemo", message);
} else if ("e".equals(logLevel)) {
Log.e("sdkDemo", message);
} else {
Log.d("sdkDemo", message);
}
activity.runOnUiThread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
if (mToast != null) {
mToast.cancel();
mToast = null;
}
mToast = Toast.makeText(activity, message, Toast.LENGTH_SHORT);
mToast.show();
}
});
}
/**
* 打印消息并且用Toast显示消息
*
* @param activity
* @param message
* @param logLevel
* 填d, w, e分别代表debug, warn, error; 默认是debug
*/
public static final void toastMessage(final Activity activity,
final String message) {
toastMessage(activity, message, null);
}
/**
* 根据一个网络连接(String)获取bitmap图像
*
* @param imageUri
* @return
* @throws MalformedURLException
*/
public static Bitmap getbitmap(String imageUri) {
Log.v(TAG, "getbitmap:" + imageUri);
// 显示网络上的图片
Bitmap bitmap = null;
try {
URL myFileUrl = new URL(imageUri);
HttpURLConnection conn = (HttpURLConnection) myFileUrl
.openConnection();
conn.setDoInput(true);
conn.connect();
InputStream is = conn.getInputStream();
bitmap = BitmapFactory.decodeStream(is);
is.close();
Log.v(TAG, "image download finished." + imageUri);
} catch (IOException e) {
e.printStackTrace();
Log.v(TAG, "getbitmap bmp fail---");
return null;
}
return bitmap;
}
}
Constants.java
package com.eeb.qqauthdemo;
public interface Constants {
public static final String QQ_APP_ID = "<span style="color: rgb(153, 153, 153); font-family: Tahoma, Helvetica, simsun; line-height: 21px;">1103438649</span>";//替换为我们自己申请的appid
}
MainActivity.java
package com.eeb.qqauthdemo;
import java.util.ArrayList;
import org.json.JSONException;
import org.json.JSONObject;
import android.app.Activity;
import android.os.Bundle;
import android.util.Log;
import android.view.View;
import android.widget.TextView;
import android.widget.Toast;
import com.tencent.connect.UserInfo;
import com.tencent.connect.auth.QQAuth;
import com.tencent.connect.share.QzoneShare;
import com.tencent.tauth.IUiListener;
import com.tencent.tauth.Tencent;
import com.tencent.tauth.UiError;
public class MainActivity extends Activity {
private QQAuth mQQAuth = null;
private Tencent mTencent = null;
private UserInfo mInfo = null;
private TextView mShowInfo = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
mQQAuth = QQAuth.createInstance(Constants.QQ_APP_ID,
this.getApplicationContext());
mTencent = Tencent.createInstance(Constants.QQ_APP_ID,
this.getApplicationContext());
initView();
}
public void initView() {
mShowInfo = (TextView) this.findViewById(R.id.show_info);
}
public void qqAuth(View view) {
startQQAuth();
}
public void shareToQQZone(View view) {
final Bundle params = new Bundle();
params.putInt(QzoneShare.SHARE_TO_QZONE_KEY_TYPE,
QzoneShare.SHARE_TO_QZONE_TYPE_IMAGE_TEXT);
params.putString(QzoneShare.SHARE_TO_QQ_TITLE, "QQ分享测试");
params.putString(QzoneShare.SHARE_TO_QQ_SUMMARY, "我是测试的,分享测试");
params.putString(QzoneShare.SHARE_TO_QQ_TARGET_URL,
"http://www.baidu.com");
ArrayList<String> imagerUrlArr = new ArrayList<String>();
imagerUrlArr.add("http://elfinland.com/images/logo.png");
params.putStringArrayList(QzoneShare.SHARE_TO_QQ_IMAGE_URL,
imagerUrlArr);
doShareToQzone(params);
}
public void getUserInfo(View view) {
if (mAccessToken != null) {
mInfo = new UserInfo(this, mQQAuth.getQQToken());
mInfo.getUserInfo(new BaseUIListener(this, "get_simple_userinfo"));
} else {
Toast("mAccessToken is null");
}
}
private String mAccessToken = null;
private void startQQAuth() {
//mQQAuth.logout(this);
if (!mQQAuth.isSessionValid()) {
IUiListener listener = new BaseUiListener() {
@Override
protected void doComplete(JSONObject values) {
mShowInfo.setText(values.toString());
try {
mAccessToken = values.getString("access_token");
} catch (JSONException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
};
mTencent.loginWithOEM(this, "all", listener, "10000144",
"10000144", "xxxx");
}
}
private class BaseUiListener implements IUiListener {
@Override
public void onComplete(Object response) {
doComplete((JSONObject) response);
}
protected void doComplete(JSONObject values) {
}
@Override
public void onError(UiError e) {
Util.toastMessage(MainActivity.this, "onError: " + e.errorDetail);
Util.dismissDialog();
}
@Override
public void onCancel() {
Util.toastMessage(MainActivity.this, "已取消授权 ");
Util.dismissDialog();
}
}
/**
* 用异步方式启动分享
*
* @param params
*/
private void doShareToQzone(final Bundle params) {
new Thread(new Runnable() {
@Override
public void run() {
// TODO Auto-generated method stub
mTencent.shareToQzone(MainActivity.this, params,
new IUiListener() {
@Override
public void onCancel() {
}
@Override
public void onError(UiError e) {
// TODO Auto-generated method stub
Log.e(" e.errorDetail", "--" + e.errorDetail);
Log.e(" e.errorCode", "--" + e.errorCode);
Log.e(" e.errorMessage", "--" + e.errorMessage);
}
@Override
public void onComplete(Object response) {
// TODO Auto-generated method stub
// Util.toastMessage(mAct, "onComplete: " +
// response.toString());
}
});
}
}).start();
}
private void Toast(String msg) {
Toast.makeText(this, msg, Toast.LENGTH_SHORT).show();
}
}
千万记得,AndroidManifest.xml
<?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
package="com.eeb.qqauthdemo"
android:versionCode="1"
android:versionName="1.0" >
<uses-sdk
android:minSdkVersion="8"
android:targetSdkVersion="18" />
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<application
android:allowBackup="true"
android:icon="@drawable/ic_launcher"
android:label="@string/app_name"
android:theme="@style/AppTheme" >
<activity
android:name="com.eeb.qqauthdemo.MainActivity"
android:label="@string/app_name" >
<intent-filter>
<action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" />
</intent-filter>
</activity>
<activity
android:name="com.tencent.connect.common.AssistActivity"
android:screenOrientation="portrait"
android:theme="@android:style/Theme.Translucent.NoTitleBar" />
<activity
android:name="com.tencent.tauth.AuthActivity"
android:launchMode="singleTask"
android:noHistory="true" >
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="tencent1103438649" />//后面的数字为appid
</intent-filter>
</activity>
</application>
</manifest>
以上代码,均可从官方demo中找到。