qq授权登录实现步骤

 

第一步,下载qq授权登录的sdk

 

 

第二步:在清单文件中添加腾讯官方的activity ,具体代码在下方

 

Activity实现:

public class MainActivity extends Activity {

       private static final String TAG = MainActivity.class.getName();

       public static String mAppid;

       private Button mNewLoginButton;

       private TextView mUserInfo;

       private ImageView mUserLogo;

       public static QQAuth mQQAuth;

       private UserInfo mInfo;

       private Tencent mTencent;

       private final String APP_ID = "222222";// 测试时使用,真正发布的时候要换成自己的APP_ID

 

       @Override

       public void onCreate(Bundle savedInstanceState) {

              super.onCreate(savedInstanceState);

              Log.d(TAG, "-->onCreate");

              // 固定竖屏

              setContentView(R.layout.activity_main);

              initViews();

       }

 

       @Override

       protected void onStart() {

              Log.d(TAG, "-->onStart");

              final Context context = MainActivity.this;

              final Context ctxContext = context.getApplicationContext();

              mAppid = APP_ID;

              mQQAuth = QQAuth.createInstance(mAppid, ctxContext);//初始化QQ权限组件

              mTencent = Tencent.createInstance(mAppid, MainActivity.this);//初始化腾讯登录组件

              super.onStart();

       }

 

       @Override

       protected void onResume() {

              Log.d(TAG, "-->onResume");

              super.onResume();

       }

 

       @Override

       protected void onPause() {

              Log.d(TAG, "-->onPause");

              super.onPause();

       }

 

       @Override

       protected void onStop() {

              Log.d(TAG, "-->onStop");

              super.onStop();

       }

 

       @Override

       protected void onDestroy() {

              Log.d(TAG, "-->onDestroy");

              super.onDestroy();

       }

 

       private void initViews() {

              mNewLoginButton = (Button) findViewById(R.id.new_login_btn);

 

              //这一步看着像是多余的 直接mNewLoginButton.setOnClickListener(listener);是一样的效果

              //你所需要的: 1->findviewbyid找到这个按钮,然后绑定点击事件

              LinearLayout linearLayout = (LinearLayout) findViewById(R.id.main_container);

              OnClickListener listener = new NewClickListener();

              for (int i = 0; i < linearLayout.getChildCount(); i++) {

                     View view = linearLayout.getChildAt(i);

                     if (view instanceof Button) {

                            view.setOnClickListener(listener);

                     }

              }

              mUserInfo = (TextView) findViewById(R.id.user_nickname);

              mUserLogo = (ImageView) findViewById(R.id.user_logo);

              updateLoginButton();

       }

 

       private void updateLoginButton() {

              if (mQQAuth != null && mQQAuth.isSessionValid()) {

                     mNewLoginButton.setTextColor(Color.RED);

                     mNewLoginButton.setText(R.string.qq_logout);

              } else {

                     mNewLoginButton.setTextColor(Color.BLUE);

                     mNewLoginButton.setText(R.string.qq_login);

              }

       }

 

       private void updateUserInfo() {

              if (mQQAuth != null && mQQAuth.isSessionValid()) {

                     IUiListener listener = new IUiListener() {

 

                            @Override

                            public void onError(UiError e) {

                                   // TODO Auto-generated method stub

 

                            }

 

                            @Override

                            public void onComplete(final Object response) {

                                   Message msg = new Message();

                                   msg.obj = response;

                                   msg.what = 0;

                                   mHandler.sendMessage(msg);

                                   new Thread() {

 

                                          @Override

                                          public void run() {

                                                 JSONObject json = (JSONObject) response;

                                                 if (json.has("figureurl")) {

                                                        Bitmap bitmap = null;

                                                        try {

                                                               bitmap = Util.getbitmap(json

                                                                             .getString("figureurl_qq_2"));

                                                        } catch (JSONException e) {

 

                                                        }

                                                        Message msg = new Message();

                                                        msg.obj = bitmap;

                                                        msg.what = 1;

                                                        mHandler.sendMessage(msg);

                                                 }

                                          }

 

                                   }.start();

                            }

 

                            @Override

                            public void onCancel() {

                            }

                     };

                     mInfo = new UserInfo(this, mQQAuth.getQQToken());

                     mInfo.getUserInfo(listener);

 

              } else {

                     mUserInfo.setText("");

                     mUserInfo.setVisibility(android.view.View.GONE);

                     mUserLogo.setVisibility(android.view.View.GONE);

              }

       }

 

       Handler mHandler = new Handler() {

 

              @Override

              public void handleMessage(Message msg) {

                     if (msg.what == 0) {

                            JSONObject response = (JSONObject) msg.obj;

                            if (response.has("nickname")) {

                                   try {

                                          mUserInfo.setVisibility(android.view.View.VISIBLE);

                                          mUserInfo.setText(response.getString("nickname"));

                                   } catch (JSONException e) {

                                          // TODO Auto-generated catch block

                                          e.printStackTrace();

                                   }

                            }

                     } else if (msg.what == 1) {

                            Bitmap bitmap = (Bitmap) msg.obj;

                            mUserLogo.setImageBitmap(bitmap);

                            mUserLogo.setVisibility(android.view.View.VISIBLE);

                     }

              }

 

       };

 

       private void onClickLogin() {

              if (!mQQAuth.isSessionValid()) {//权限通过

                     IUiListener listener = new BaseUiListener() {

                            @Override

                            protected void doComplete(JSONObject values) {

                                   updateUserInfo();

                                   updateLoginButton();

                            }

                     };

                     mQQAuth.login(this, "all", listener);

                     // mTencent.loginWithOEM(this, "all",

                     // listener,"10000144","10000144","xxxx");

                     mTencent.login(this, "all", listener);

              } else {

                     mQQAuth.logout(this);

                     updateUserInfo();

                     updateLoginButton();

              }

       }

 

       public static boolean ready(Context context) {

              if (mQQAuth == null) {

                     return false;

              }

              boolean ready = mQQAuth.isSessionValid()

                            && mQQAuth.getQQToken().getOpenId() != null;

              if (!ready)

                     Toast.makeText(context, "login and get openId first, please!",

                                   Toast.LENGTH_SHORT).show();

              return ready;

       }

 

       private class BaseUiListener implements IUiListener {

 

              @Override

              public void onComplete(Object response) {

                     Util.showResultDialog(MainActivity.this, response.toString(),

                                   "登录成功");

                     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, "onCancel: ");

                     Util.dismissDialog();

              }

       }

 

 

       class NewClickListener implements OnClickListener {

              @Override

              public void onClick(View v) {

                     //2->点击事件里使用这个

                     Context context = v.getContext();

                     Class<?> cls = null;

                     switch (v.getId()) {

                     case R.id.new_login_btn:

                            onClickLogin();

                            return;

                     }

                     if (cls != null) {

                            Intent intent = new Intent(context, cls);

                            context.startActivity(intent);

                     }

              }

       }

}

 

Util类的写法:

 

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;

       }

}

 

activity_main布局:

<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"

    android:layout_width="fill_parent"

    android:layout_height="fill_parent"

    android:orientation="vertical"

    android:paddingBottom="25dp"

    android:paddingLeft="10dp"

    android:paddingRight="10dp"

    android:paddingTop="25dp" >

 

    <ScrollView

        android:layout_width="match_parent"

        android:layout_height="match_parent" >

 

        <LinearLayout

            android:id="@+id/main_container"

            android:layout_width="match_parent"

            android:layout_height="wrap_content"

            android:orientation="vertical" >

 

            <LinearLayout

                android:layout_width="wrap_content"

                android:layout_height="wrap_content"

                android:orientation="horizontal" >

 

                <ImageView

                    android:id="@+id/user_logo"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:visibility="gone" />

 

                <TextView

                    android:id="@+id/user_nickname"

                    android:layout_width="wrap_content"

                    android:layout_height="wrap_content"

                    android:textColor="#80505050"

                    android:textSize="18sp"

                    android:visibility="gone" />

            </LinearLayout>

 

            <Button

                android:id="@+id/new_login_btn"

                android:layout_width="match_parent"

                android:layout_height="wrap_content" />

        </LinearLayout>

    </ScrollView>

 

</LinearLayout>

 

清单文件代码:

<?xml version="1.0" encoding="utf-8"?>

<manifest xmlns:android="http://schemas.android.com/apk/res/android"

    package="com.example.qqloginsample"

    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" />

    <uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />

    <!-- SDK2.1新增获取用户位置信息 -->

    <uses-permission android:name="android.permission.ACCESS_FINE_LOCATION" />

    <uses-permission android:name="android.permission.ACCESS_COARSE_LOCATION" />

    <uses-permission android:name="android.permission.ACCESS_LOCATION_EXTRA_COMMANDS" />

    <uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />

    <uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

    <uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />

    <uses-permission android:name="android.permission.READ_PHONE_STATE" />

 

    <application

        android:allowBackup="true"

        android:icon="@drawable/ic_launcher"

        android:label="@string/app_name"

        android:theme="@style/AppTheme" >

        <activity

            android:name=".MainActivity"

            android:screenOrientation="portrait"

            >

            <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:configChanges="orientation|keyboardHidden"

            android:screenOrientation="portrait"

            android:theme="@android:style/Theme.Translucent.NoTitleBar" />

        <activity

            android:name=".ReturnActivity"

             >

        </activity>

        <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="tencent222222" />

                           <!-- 100380359 100381104 222222 -->

            </intent-filter>

        </activity>

      

    </application>

 

 

</manifest>

如需要源码请点这里

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值