Commit a8e3b987 authored by zhengyingbing's avatar zhengyingbing
Browse files

feat(app): 接入demo更新

parent fd25d4fc
...@@ -3,39 +3,14 @@ apply plugin: 'com.android.application' ...@@ -3,39 +3,14 @@ apply plugin: 'com.android.application'
android { android {
compileSdkVersion 29 compileSdkVersion 29
defaultConfig { defaultConfig {
// applicationId "com.hoolai.sdsxszycsgz" applicationId "com.hoolai.access.demo"
applicationId "com.hoolai.sdsxszycs" minSdkVersion 21
minSdkVersion 19
targetSdkVersion 29 targetSdkVersion 29
versionCode 1 versionCode 1
versionName "1.0" versionName "1.0"
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase()) manifestPlaceholders.put("APPLOG_SCHEME","rangersapplog.byAx6uYt".toLowerCase())
} }
signingConfigs {
release { //todo 需要换成正确的keystore
storeFile file("..\\keystoreFile\\sds.keystore")
keyPassword 'hoolai'
storePassword 'hoolai'
keyAlias 'ft'
}
test { //todo 需要换成正确的keystore
storeFile file("..\\keystoreFile\\sds_debug.keystore")
keyPassword 'hoolai321'
storePassword 'hoolai321'
keyAlias 'access-debug'
}
}
buildTypes {
release {
signingConfig signingConfigs.release
minifyEnabled false
proguardFiles getDefaultProguardFile('proguard-android-optimize.txt'), 'proguard-rules.pro'
}
debug {
signingConfig signingConfigs.release
}
}
compileOptions { compileOptions {
sourceCompatibility JavaVersion.VERSION_1_8 sourceCompatibility JavaVersion.VERSION_1_8
targetCompatibility JavaVersion.VERSION_1_8 targetCompatibility JavaVersion.VERSION_1_8
...@@ -43,6 +18,5 @@ android { ...@@ -43,6 +18,5 @@ android {
} }
dependencies { dependencies {
//官网渠道 implementation 'com.hoolai.access.open:hoolai-core:1.0.1.1'
implementation 'com.hoolai.access.channel:hoolai-sdk:1.0.0.9'
} }
\ No newline at end of file
package com.hl.account;
import android.content.Context;
import androidx.test.platform.app.InstrumentationRegistry;
import androidx.test.ext.junit.runners.AndroidJUnit4;
import org.junit.Test;
import org.junit.runner.RunWith;
import static org.junit.Assert.*;
/**
* Instrumented test, which will execute on an Android device.
*
* @see <a href="http://d.android.com/tools/testing">Testing documentation</a>
*/
@RunWith(AndroidJUnit4.class)
public class ExampleInstrumentedTest {
@Test
public void useAppContext() {
// Context of the app under test.
Context appContext = InstrumentationRegistry.getInstrumentation().getTargetContext();
assertEquals("com.hl.account", appContext.getPackageName());
}
}
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<manifest xmlns:android="http://schemas.android.com/apk/res/android" <manifest xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools" package="com.hl.demo">
package="com.hoolai.demo">
<!--hoolai sdk permission start-->
<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.READ_SYNC_STATS" />
<uses-permission android:name="android.permission.READ_PHONE_STATE" />
<uses-permission android:name="android.permission.READ_CONTACTS" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />
<uses-permission android:name="android.permission.ACCESS_WIFI_STATE" />
<uses-permission android:name="android.permission.WRITE_EXTERNAL_STORAGE" />
<uses-permission android:name="android.permission.CHANGE_WIFI_STATE" />
<uses-permission android:name="android.permission.CHANGE_NETWORK_STATE" />
<uses-permission android:name="android.permission.READ_EXTERNAL_STORAGE" />
<application <application
android:name="com.hl.demo.GameApplication" android:name=".GameApplication"
android:allowBackup="true" android:allowBackup="true"
android:label="@string/app_name" android:icon="@mipmap/ic_launcher"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen" android:label="fastSdkDemo"
android:roundIcon="@mipmap/ic_launcher_round"
android:supportsRtl="true" android:supportsRtl="true"
android:networkSecurityConfig="@xml/network_security_config" android:theme="@android:style/Theme.Translucent.NoTitleBar.Fullscreen"
android:usesCleartextTraffic="true"> android:usesCleartextTraffic="true">
<activity <activity
android:name="com.hl.demo.GameActivity" android:name=".MainActivity"
android:configChanges="keyboardHidden|orientation|screenSize" android:exported="true">
android:screenOrientation="portrait">
<intent-filter> <intent-filter>
<action android:name="android.intent.action.MAIN" /> <action android:name="android.intent.action.MAIN" />
<category android:name="android.intent.category.LAUNCHER" /> <category android:name="android.intent.category.LAUNCHER" />
</intent-filter> </intent-filter>
</activity> </activity>
</application> </application>
</manifest> </manifest>
\ No newline at end of file
MHZP8CM4NNqRrgaSiTk8XYroIMwKJVeLkdj5GZxI7y9kstf+a3YDUeEvsc5M/CIFf5SlzOYCw7KJ1SRv+BC7bzRbUwAsBlA7xUS6H91WdlEo3evStrXFC3mHjgbBudche1GuGdxubrnLkj7cBDi7hzjlw+Yv5ZikR252K8r7isKx9+zN5WLw8OXm5O0K4soIegPNNv5XhvYGiCHEKda84NDbFmIma1Ipq22cHZ/i3+omwSHxGhz94iUoChdiQ6f5l6cqtO+An3F862I1TVe9CkpfRolEhhaiqFElkKhK/rMIg4QGZIC0VVEAGU8HHtBEEvTxApvO2dYbeCE1fLmYZQ==
\ No newline at end of file
package com.hl.account;
import android.content.ComponentName;
import android.content.Context;
import android.content.Intent;
import android.content.ServiceConnection;
import android.content.pm.PackageManager;
import android.os.IBinder;
import android.os.IInterface;
import android.os.Looper;
import android.os.Parcel;
import android.os.RemoteException;
import java.util.concurrent.LinkedBlockingQueue;
public class AdvertisingIdClient {
/**
* 这个方法是耗时的,不能在主线程调用
*/
public static String getGoogleAdId(Context context) throws Exception {
if (Looper.getMainLooper() == Looper.myLooper()) {
return "Cannot call in the main thread, You must call in the other thread";
}
PackageManager pm = context.getPackageManager();
pm.getPackageInfo("com.android.vending", 0);
AdvertisingConnection connection = new AdvertisingConnection();
Intent intent = new Intent(
"com.google.android.gms.ads.identifier.service.START");
intent.setPackage("com.google.android.gms");
if (context.bindService(intent, connection, Context.BIND_AUTO_CREATE)) {
try {
AdvertisingInterface adInterface = new AdvertisingInterface(
connection.getBinder());
return adInterface.getId();
} finally {
context.unbindService(connection);
}
}
return "";
}
private static final class AdvertisingConnection implements ServiceConnection {
boolean retrieved = false;
private final LinkedBlockingQueue<IBinder> queue = new LinkedBlockingQueue<>(1);
public void onServiceConnected(ComponentName name, IBinder service) {
try {
this.queue.put(service);
} catch (InterruptedException localInterruptedException) {
}
}
public void onServiceDisconnected(ComponentName name) {
}
public IBinder getBinder() throws InterruptedException {
if (this.retrieved)
throw new IllegalStateException();
this.retrieved = true;
return this.queue.take();
}
}
private static final class AdvertisingInterface implements IInterface {
private IBinder binder;
public AdvertisingInterface(IBinder pBinder) {
binder = pBinder;
}
public IBinder asBinder() {
return binder;
}
public String getId() throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
String id;
try {
data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
binder.transact(1, data, reply, 0);
reply.readException();
id = reply.readString();
} finally {
reply.recycle();
data.recycle();
}
return id;
}
public boolean isLimitAdTrackingEnabled(boolean paramBoolean) throws RemoteException {
Parcel data = Parcel.obtain();
Parcel reply = Parcel.obtain();
boolean limitAdTracking;
try {
data.writeInterfaceToken("com.google.android.gms.ads.identifier.internal.IAdvertisingIdService");
data.writeInt(paramBoolean ? 1 : 0);
binder.transact(2, data, reply, 0);
reply.readException();
limitAdTracking = 0 != reply.readInt();
} finally {
reply.recycle();
data.recycle();
}
return limitAdTracking;
}
}
}
package com.hl.account;
import android.content.Context;
import android.text.TextUtils;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* Created by Administrator on 2017/8/15.
*/
public class AppUtil {
/**
* 判断email格式是否正确
*
* @param email
* @return true:是邮箱
*/
public static boolean isEmail(String email) {
if (TextUtils.isEmpty(email)) {
return false;
}
String str = "^([a-zA-Z0-9_\\-\\.]+)@((\\[[0-9]{1,3}\\.[0-9]{1,3}\\.[0-9]{1,3}\\.)|(" +
"" + "([a-zA-Z0-9\\-]+\\.)+))([a-zA-Z]{2,4}|[0-9]{1,3})(\\]?)$";
Pattern p = Pattern.compile(str);
Matcher m = p.matcher(email);
return m.matches();
}
/**
* 判断密码是否合法
*/
public static String isPwd(Context context, String pwd) {
if (TextUtils.isEmpty(pwd)) {
return context.getResources().getString(RTools.getString(context,
"lksea_please_input_password"));
}
if (pwd.contains(" ") || isChinese(pwd)) {
return context.getString(RTools.getString(context, "lksea_password_not_comply_rules"));
}
int length = pwd.length();
for (int i = 0; i < length; i++) {
char charAt = pwd.charAt(i);
boolean chinese = isChinese(charAt);
if (chinese) {
return context.getString(RTools.getString(context, "lksea_no_space"));
}
}
if (length < 6 || length > 31) {
return context.getString(RTools.getString(context, "lksea_length_error"));
}
String reg = "^[a-zA-Z0-9]+[.a-zA-Z0-9@_-]*$";
Pattern pattern = Pattern.compile(reg);
Matcher matcher = pattern.matcher(pwd);
if (!matcher.matches()) {
return context.getString(RTools.getString(context, "lksea_format_error"));
}
return null;
}
/**
* 判断字符串是否是中文
*
* @param str 字符串
*/
public static boolean isChinese(String str) {
char[] ch = str.toCharArray();
for (int i = 0; i < ch.length; i++) {
char c = ch[i];
if (isChinese(c)) {
return true;
}
}
return false;
}
// 根据Unicode编码完美的判断中文汉字和符号
private static boolean isChinese(char c) {
Character.UnicodeBlock ub = Character.UnicodeBlock.of(c);
if (ub == Character.UnicodeBlock.CJK_UNIFIED_IDEOGRAPHS || ub == Character.UnicodeBlock
.CJK_COMPATIBILITY_IDEOGRAPHS || ub == Character.UnicodeBlock
.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_A || ub == Character.UnicodeBlock
.CJK_UNIFIED_IDEOGRAPHS_EXTENSION_B || ub == Character.UnicodeBlock
.CJK_SYMBOLS_AND_PUNCTUATION || ub == Character.UnicodeBlock
.HALFWIDTH_AND_FULLWIDTH_FORMS || ub == Character.UnicodeBlock
.GENERAL_PUNCTUATION) {
return true;
}
return false;
}
/**
* 判断手机格式是否正确
*
* @param mobiles
* @return true:是手机号
*/
public static boolean isMobileNumber(String mobiles) {
Pattern p = Pattern.compile("^((13[0-9])|(15[^4,\\D])|(18[0,5-9]))\\d{8}$");
Matcher m = p.matcher(mobiles);
return m.matches();
}
/**
* 判断验证码长度是否为6位,并且全为数字
*
* @param verificationCode
* @return 是否是验证码
*/
public static boolean isVerification(String verificationCode) {
if (verificationCode.length() != 6) {
return false;
}
Pattern pattern = Pattern.compile("[0-9]*");
Matcher matcher = pattern.matcher(verificationCode);
return matcher.matches();
}
/**
* 账号部分用*代替,隐藏内容
*
* @param passport
* @return 186****1234
*/
public static String showAccount(String passport) {
int flag = passport.indexOf("@");
String replaceSymbol = "*";
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < passport.length(); i++) {
char number = passport.charAt(i);
if (i >= 2 && i < flag - 2) {
stringBuilder.append(replaceSymbol);
} else {
stringBuilder.append(number);
}
}
return stringBuilder.toString();
}
public static int px2dip(Context context, float pxValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (pxValue / scale + 0.5f);
}
/**
* 根据手机的分辨率从 dp 的单位 转成为 px(像素)
*/
public static int dip2px(Context context, float dpValue) {
final float scale = context.getResources().getDisplayMetrics().density;
return (int) (dpValue * scale + 0.5f);
}
}
package com.hl.account;
import java.io.UnsupportedEncodingException;
/**
* Description:
* Author: Hansion
* Time: 2017/8/10 10:40
*/
public class Base64Utils {
private static char[] base64EncodeChars = new char[]
{ 'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M', 'N', 'O', 'P', 'Q', 'R', 'S', 'T',
'U', 'V', 'W', 'X', 'Y', 'Z', 'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',
'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z', '0', '1', '2', '3', '4', '5',
'6', '7', '8', '9', '+', '/' };
private static byte[] base64DecodeChars = new byte[]
{ -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, 62, -1, -1, -1, 63, 52, 53,
54, 55, 56, 57, 58, 59, 60, 61, -1, -1, -1, -1, -1, -1, -1, 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11,
12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, -1, -1, -1, -1, -1, -1, 26, 27, 28, 29,
30, 31, 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47, 48, 49, 50, 51, -1, -1,
-1, -1, -1 };
/**
* 加密
*
* @param data
* @return 加密报文
*/
public static String encode(byte[] data)
{
StringBuffer sb = new StringBuffer();
int len = data.length;
int i = 0;
int b1, b2, b3;
while (i < len)
{
b1 = data[i++] & 0xff;
if (i == len)
{
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[(b1 & 0x3) << 4]);
sb.append("==");
break;
}
b2 = data[i++] & 0xff;
if (i == len)
{
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[(b2 & 0x0f) << 2]);
sb.append("=");
break;
}
b3 = data[i++] & 0xff;
sb.append(base64EncodeChars[b1 >>> 2]);
sb.append(base64EncodeChars[((b1 & 0x03) << 4) | ((b2 & 0xf0) >>> 4)]);
sb.append(base64EncodeChars[((b2 & 0x0f) << 2) | ((b3 & 0xc0) >>> 6)]);
sb.append(base64EncodeChars[b3 & 0x3f]);
}
return sb.toString();
}
/**
* 解密
*
* @param str
* @return byte数组
*/
public static byte[] decode(String str)
{
try
{
return decodePrivate(str);
} catch (UnsupportedEncodingException e)
{
e.printStackTrace();
}
return new byte[]
{};
}
private static byte[] decodePrivate(String str) throws UnsupportedEncodingException
{
StringBuffer sb = new StringBuffer();
byte[] data = str.getBytes("US-ASCII");
int len = data.length;
int i = 0;
int b1, b2, b3, b4;
while (i < len)
{
do
{
b1 = base64DecodeChars[data[i++]];
} while (i < len && b1 == -1);
if (b1 == -1)
break;
do
{
b2 = base64DecodeChars[data[i++]];
} while (i < len && b2 == -1);
if (b2 == -1)
break;
sb.append((char) ((b1 << 2) | ((b2 & 0x30) >>> 4)));
do
{
b3 = data[i++];
if (b3 == 61)
return sb.toString().getBytes("iso8859-1");
b3 = base64DecodeChars[b3];
} while (i < len && b3 == -1);
if (b3 == -1)
break;
sb.append((char) (((b2 & 0x0f) << 4) | ((b3 & 0x3c) >>> 2)));
do
{
b4 = data[i++];
if (b4 == 61)
return sb.toString().getBytes("iso8859-1");
b4 = base64DecodeChars[b4];
} while (i < len && b4 == -1);
if (b4 == -1)
break;
sb.append((char) (((b3 & 0x03) << 6) | b4));
}
return sb.toString().getBytes("iso8859-1");
}
}
package com.hl.account;
import android.annotation.SuppressLint;
import android.content.Context;
import android.os.CountDownTimer;
import android.util.AttributeSet;
import android.widget.Button;
/**
* 倒计时按钮
*/
@SuppressLint("AppCompatCustomView")
public class CounterDownButton extends Button {
private CounterDown counterDown;
private Context mContext;
public boolean isRunning = false;
public CounterDownButton(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
mContext = context;
init();
}
public CounterDownButton(Context context, AttributeSet attrs) {
super(context, attrs);
mContext = context;
init();
}
public CounterDownButton(Context context) {
super(context);
mContext = context;
init();
}
private void init() {
counterDown = new CounterDown(60 * 1000, 1000);
}
public void start() {
if (counterDown != null) {
counterDown.start();
isRunning = true;
}
setEnabled(false);
}
public void cancle() {
if (counterDown != null) {
counterDown.cancel();
isRunning = false;
}
setText(mContext.getResources().getString(RTools.getString(mContext, "lksea_send_again")));
setEnabled(true);
}
private class CounterDown extends CountDownTimer {
public CounterDown(long millisInFuture, long countDownInterval) {
super(millisInFuture, countDownInterval);
}
@Override
public void onFinish() {
setText(mContext.getResources().getString(RTools.getString(mContext,
"lksea_send_again")));
setEnabled(true);
isRunning = false;
}
@Override
public void onTick(long millisUntilFinished) {
String format = mContext.getResources().getString(RTools.getString(mContext,
"lksea_second_after_send_again"));
setText(String.format(format, (millisUntilFinished / 1000)));
}
}
}
package com.hl.account;
import android.content.Context;
import android.provider.Settings.Secure;
import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.RandomAccessFile;
import java.util.UUID;
public class DeviceUtils {
/**
* 获取当前时间
* */
public static long getNowTime(){
return System.currentTimeMillis() / 1000;
}
/**************************** UUID框架 ***********************************/
private static String sID = null;
private static final String INSTALLATION = "INSTALLATION";
public synchronized static String id(Context context) {
if (sID == null) {
File installation = new File(context.getFilesDir(), INSTALLATION);
try {
if (!installation.exists()) {
writeInstallationFile(context, installation);
}
sID = readInstallationFile(installation);
} catch (Exception e) {
throw new RuntimeException(e);
}
}
return sID;
}
private static String readInstallationFile(File installation) throws IOException {
RandomAccessFile f = new RandomAccessFile(installation, "r");
byte[] bytes = new byte[(int) f.length()];
f.readFully(bytes);
f.close();
return new String(bytes);
}
private static void writeInstallationFile(Context context, File installation) throws IOException {
FileOutputStream out = new FileOutputStream(installation);
String id;
final String androidId = Secure.getString(context.getContentResolver(), Secure.ANDROID_ID);
if (androidId == null) {
id = UUID.randomUUID().toString();
} else {
if (!"9774d56d682e549c".equals(androidId)) {
id = androidId;
} else {
id = UUID.randomUUID().toString();
}
}
out.write(id.getBytes());
out.close();
}
/**************************** UUID框架 ***********************************/
}
package com.hl.account;
import android.annotation.SuppressLint;
import android.content.Context;
import android.util.AttributeSet;
import android.view.View;
import android.view.View.OnClickListener;
import android.widget.ImageView;
@SuppressLint("AppCompatCustomView")
public class LogoView extends ImageView implements OnClickListener {
// logo五次点击显示版本号
private int size = 5;
private long[] clicks = new long[size];
private Context cxt;
public LogoView(Context context) {
super(context);
cxt = context;
setOnClickListener(this);
}
public LogoView(Context context, AttributeSet attrs) {
super(context, attrs);
cxt = context;
setOnClickListener(this);
}
public LogoView(Context context, AttributeSet attrs, int defStyle) {
super(context, attrs, defStyle);
cxt = context;
setOnClickListener(this);
}
@Override
public void onClick(View view) {
for (int i = 0; i < size - 1; i++) {
clicks[i] = clicks[i + 1];
}
clicks[size - 1] = System.currentTimeMillis();
if ((clicks[size - 1] - clicks[0]) < 1500) {
// Toast.makeText(cxt, LKBuild.VERSION, Toast.LENGTH_LONG).show();
if (mClickFastListener != null){
mClickFastListener.onClickfast();
}
for (int i = 0; i < size; i++) {
clicks[i] = 0;
}
}
}
private OnClickFastListener mClickFastListener;
public void setClickFastListener(OnClickFastListener listener){
mClickFastListener = listener;
}
public interface OnClickFastListener{
void onClickfast();
}
}
\ No newline at end of file
package com.hl.account;
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.hoolai.demo.R;
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
}
}
package com.hl.account;
import java.security.KeyFactory;
import java.security.KeyPair;
import java.security.KeyPairGenerator;
import java.security.NoSuchAlgorithmException;
import java.security.PrivateKey;
import java.security.PublicKey;
import java.security.Signature;
import java.security.interfaces.RSAPrivateKey;
import java.security.interfaces.RSAPublicKey;
import java.security.spec.InvalidKeySpecException;
import java.security.spec.PKCS8EncodedKeySpec;
import java.security.spec.X509EncodedKeySpec;
import java.util.ArrayList;
import java.util.List;
import javax.crypto.Cipher;
/**
* Description:
* Author: Hansion
* Time: 2017/8/10 10:34
*/
public class RSAUtils {
public static final int DEFAULT_KEY_SIZE = 2048;//秘钥默认长度
public static final String RSA = "RSA";// 非对称加密密钥算法
public static final String ECB_PKCS1_PADDING = "RSA/ECB/PKCS1Padding";//加密填充方式
public static final byte[] DEFAULT_SPLIT = "#PART#".getBytes(); // 当要加密的内容超过bufferSize,则采用partSplit进行分块加密
public static final int DEFAULT_BUFFERSIZE = (DEFAULT_KEY_SIZE / 8) - 11;// 当前秘钥支持加密的最大字节数
public static final String SIGNATURE_ALGORITHM = "MD5withRSA";
private static RSAPublicKey publicKey = null;
/**
* RSA公钥
*/
public static final String PUBLIC_KEY = "MIGfMA0GCSqGSIb3DQEBAQUAA4GNADCBiQKBgQCHOjIs2536Hq15DJ+Rijp5aZrSxBVbgRqgW+z6\n" +
"Bu/hZ3izKLRBIw8mLR79NgCi0zPNzVv8ppSVN25PIqbKmY09uI/gHXeyNDqq5nCrpZJ53IOLylZf\n" +
"JHSS+RGAhA8+B54AMZQyaDyIdkdpG+dQUqqmY1yKPEX6TObt6rtjmG9mqwIDAQAB";
/**
* 从字符串中加载公钥
*/
public static void loadPublicKey() {
try {
byte[] buffer = Base64Utils.decode(PUBLIC_KEY);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
publicKey = (RSAPublicKey) keyFactory.generatePublic(keySpec);
} catch (Exception e) {
e.printStackTrace();
}
}
/**
* 用公钥对字符串进行分段加密
*/
public static String encryptByPublicKeyForSpilt(byte[] data) throws Exception {
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return Base64Utils.encode(encryptByPublicKey(data, publicKey.getEncoded()));
}
List<Byte> allBytes = new ArrayList<Byte>(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPublicKey(buf, publicKey.getEncoded());
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return Base64Utils.encode(bytes);
}
/**
* 用公钥对字符串进行分段加密
*/
public static String encryptByPublicKey(String str) throws Exception {
byte[] data = str.getBytes();
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return Base64Utils.encode(encryptByPublicKey(data, publicKey.getEncoded()));
}
List<Byte> allBytes = new ArrayList<Byte>(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPublicKey(buf, publicKey.getEncoded());
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return Base64Utils.encode(bytes);
}
/**
* 随机生成RSA密钥对
*
* @param keyLength 密钥长度,范围:512~2048
* 一般1024
* @return
*/
public static KeyPair generateRSAKeyPair(int keyLength) {
try {
KeyPairGenerator kpg = KeyPairGenerator.getInstance(RSA);
kpg.initialize(keyLength);
return kpg.genKeyPair();
} catch (NoSuchAlgorithmException e) {
e.printStackTrace();
return null;
}
}
/**
* 用公钥对字符串进行加密
*
* @param data 原文
*/
public static byte[] encryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 加密数据
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.ENCRYPT_MODE, keyPublic);
return cp.doFinal(data);
}
/**
* 私钥加密
*
* @param data 待加密数据
* @param privateKey 密钥
* @return byte[] 加密数据
*/
public static byte[] encryptByPrivateKey(byte[] data, byte[] privateKey) throws Exception {
// 得到私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 数据加密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.ENCRYPT_MODE, keyPrivate);
return cipher.doFinal(data);
}
/**
* 公钥解密
*
* @param data 待解密数据
* @param publicKey 密钥
* @return byte[] 解密数据
*/
public static byte[] decryptByPublicKey(byte[] data, byte[] publicKey) throws Exception {
// 得到公钥
X509EncodedKeySpec keySpec = new X509EncodedKeySpec(publicKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PublicKey keyPublic = kf.generatePublic(keySpec);
// 数据解密
Cipher cipher = Cipher.getInstance(ECB_PKCS1_PADDING);
cipher.init(Cipher.DECRYPT_MODE, keyPublic);
return cipher.doFinal(data);
}
/**
* 使用私钥进行解密
*/
public static byte[] decryptByPrivateKey(byte[] encrypted, byte[] privateKey) throws Exception {
// 得到私钥
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(privateKey);
KeyFactory kf = KeyFactory.getInstance(RSA);
PrivateKey keyPrivate = kf.generatePrivate(keySpec);
// 解密数据
Cipher cp = Cipher.getInstance(ECB_PKCS1_PADDING);
cp.init(Cipher.DECRYPT_MODE, keyPrivate);
byte[] arr = cp.doFinal(encrypted);
return arr;
}
/**
* 从字符串中加载私钥<br>
*
* @param privateKeyStr
* @return
* @throws Exception
*/
public static RSAPrivateKey loadPrivateKey(String privateKeyStr) throws Exception {
try {
byte[] buffer = Base64Utils.decode(privateKeyStr);
// X509EncodedKeySpec keySpec = new X509EncodedKeySpec(buffer);
PKCS8EncodedKeySpec keySpec = new PKCS8EncodedKeySpec(buffer);
KeyFactory keyFactory = KeyFactory.getInstance(RSA);
return (RSAPrivateKey) keyFactory.generatePrivate(keySpec);
} catch (NoSuchAlgorithmException e) {
throw new Exception("无此算法");
} catch (InvalidKeySpecException e) {
throw new Exception("私钥非法");
} catch (NullPointerException e) {
throw new Exception("私钥数据为空");
}
}
/**
* 用私钥对字符串进行分段加密
*
* @param data 要加密的原始数据
* @param privateKey 秘钥
*/
public static byte[] encryptByPrivateKeyForSpilt(byte[] data, byte[] privateKey) throws Exception {
int dataLen = data.length;
if (dataLen <= DEFAULT_BUFFERSIZE) {
return encryptByPrivateKey(data, privateKey);
}
List<Byte> allBytes = new ArrayList<Byte>(2048);
int bufIndex = 0;
int subDataLoop = 0;
byte[] buf = new byte[DEFAULT_BUFFERSIZE];
for (int i = 0; i < dataLen; i++) {
buf[bufIndex] = data[i];
if (++bufIndex == DEFAULT_BUFFERSIZE || i == dataLen - 1) {
subDataLoop++;
if (subDataLoop != 1) {
for (byte b : DEFAULT_SPLIT) {
allBytes.add(b);
}
}
byte[] encryptBytes = encryptByPrivateKey(buf, privateKey);
for (byte b : encryptBytes) {
allBytes.add(b);
}
bufIndex = 0;
if (i == dataLen - 1) {
buf = null;
} else {
buf = new byte[Math.min(DEFAULT_BUFFERSIZE, dataLen - i - 1)];
}
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
* 公钥分段解密
*
* @param encrypted 待解密数据
* @param publicKey 密钥
*/
public static byte[] decryptByPublicKeyForSpilt(byte[] encrypted, byte[] publicKey) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPublicKey(encrypted, publicKey);
}
int dataLen = encrypted.length;
List<Byte> allBytes = new ArrayList<Byte>(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最后了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 这个是以split[0]开头
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 没有超出data的范围
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,则已经匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPublicKey(part, publicKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
/**
* 使用私钥分段解密
*/
public static byte[] decryptByPrivateKeyForSpilt(byte[] encrypted, byte[] privateKey) throws Exception {
int splitLen = DEFAULT_SPLIT.length;
if (splitLen <= 0) {
return decryptByPrivateKey(encrypted, privateKey);
}
int dataLen = encrypted.length;
List<Byte> allBytes = new ArrayList<Byte>(1024);
int latestStartIndex = 0;
for (int i = 0; i < dataLen; i++) {
byte bt = encrypted[i];
boolean isMatchSplit = false;
if (i == dataLen - 1) {
// 到data的最后了
byte[] part = new byte[dataLen - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part, privateKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
} else if (bt == DEFAULT_SPLIT[0]) {
// 这个是以split[0]开头
if (splitLen > 1) {
if (i + splitLen < dataLen) {
// 没有超出data的范围
for (int j = 1; j < splitLen; j++) {
if (DEFAULT_SPLIT[j] != encrypted[i + j]) {
break;
}
if (j == splitLen - 1) {
// 验证到split的最后一位,都没有break,则表明已经确认是split段
isMatchSplit = true;
}
}
}
} else {
// split只有一位,则已经匹配了
isMatchSplit = true;
}
}
if (isMatchSplit) {
byte[] part = new byte[i - latestStartIndex];
System.arraycopy(encrypted, latestStartIndex, part, 0, part.length);
byte[] decryptPart = decryptByPrivateKey(part, privateKey);
for (byte b : decryptPart) {
allBytes.add(b);
}
latestStartIndex = i + splitLen;
i = latestStartIndex - 1;
}
}
byte[] bytes = new byte[allBytes.size()];
{
int i = 0;
for (Byte b : allBytes) {
bytes[i++] = b.byteValue();
}
}
return bytes;
}
//***************************签名和验证*******************************
public static byte[] sign(byte[] data, PrivateKey priK) throws Exception {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initSign(priK);
sig.update(data);
return sig.sign();
}
public static boolean verify(byte[] data, byte[] sign, PublicKey pubK) throws Exception {
Signature sig = Signature.getInstance(SIGNATURE_ALGORITHM);
sig.initVerify(pubK);
sig.update(data);
return sig.verify(sign);
}
}
package com.hl.account;
import android.content.Context;
/**
* Created by Administrator on 2017/10/27.
*/
public class RTools {
public static int getString(Context context, String name) {
return context.getResources().getIdentifier(name, "string", context.getPackageName());
}
public static int getLayout(Context context, String name) {
return context.getResources().getIdentifier(name, "layout", context.getPackageName());
}
public static int getId(Context context, String name) {
return context.getResources().getIdentifier(name, "id", context.getPackageName());
}
public static int getDrawable(Context context, String name) {
return context.getResources().getIdentifier(name, "drawable", context.getPackageName());
}
public static int getStyle(Context context, String name) {
return context.getResources().getIdentifier(name, "style", context.getPackageName());
}
public static int getColor(Context context, String name) {
return context.getResources().getIdentifier(name, "color", context.getPackageName());
}
public static int getDimen(Context context, String name) {
return context.getResources().getIdentifier(name, "dimen", context.getPackageName());
}
}
package com.hl.account;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.LinkedBlockingQueue;
import java.util.concurrent.ScheduledExecutorService;
import java.util.concurrent.ScheduledThreadPoolExecutor;
import java.util.concurrent.SynchronousQueue;
import java.util.concurrent.ThreadFactory;
import java.util.concurrent.ThreadPoolExecutor;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.atomic.AtomicInteger;
/**
* 线程池管理类
*
* @author changcsw 2015-11-6
*
*/
public final class ThreadPoolManager {
// 获取CPU
private static final int CPU_COUNT = Runtime.getRuntime().availableProcessors();
// 线程池中最少的线程的数量
private static final int CORE_POOL_SIZE = (CPU_COUNT + 1) > 3 ? (CPU_COUNT + 1) : 3;
// 线程池中最多的线程的数量
private static final int MAXIMUM_POOL_SIZE = (CPU_COUNT > 1) ? (CPU_COUNT * 2 + 1) : 5;
// 空闲线程的最长存活时间
private static final long KEEP_ALIVE = 1L;
// 工作队列-阻塞队列
private static final BlockingQueue<Runnable> WORK_QUEUE = new LinkedBlockingQueue<Runnable>(128);
// 线程池中线程的创建工厂
private static final ThreadFactory THREAD_FACTORY = new ThreadFactory() {
// 原子操作级别的整数,初始值是1
private final AtomicInteger mCount = new AtomicInteger(1);
@Override
public Thread newThread(Runnable r) {
Thread thread = new Thread(r, "Thread #" + mCount.getAndIncrement()); // 线程名,前缀固定,后缀自增长
thread.setPriority(Thread.NORM_PRIORITY); // 正常优先级
return thread;
}
};
/************************************** 线程池中线程的执行的管理器 ******************************************/
// 普通的任务用这个执行器, 缺点:当没有任务是还会CORE_POOL_SIZE个线程占用资源,优点:无需频繁调度
public static final ExecutorService EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, MAXIMUM_POOL_SIZE,
KEEP_ALIVE, TimeUnit.SECONDS, WORK_QUEUE, THREAD_FACTORY, new ThreadPoolExecutor.DiscardPolicy());
// 有新的任务就开启新的线程,当没有新任务时会自动回收线程,缺点:频繁调度, 优点:快速处理任务
public static final ExecutorService CACHED_EXECUTOR = new ThreadPoolExecutor(CORE_POOL_SIZE, Integer.MAX_VALUE,
60L, TimeUnit.SECONDS, new SynchronousQueue<Runnable>(), THREAD_FACTORY,
new ThreadPoolExecutor.DiscardOldestPolicy());
// 当有计划的执行一个任务时用,如检查版本更新,
public static final ScheduledExecutorService SCHEDULED_EXECUTOR = new ScheduledThreadPoolExecutor(CORE_POOL_SIZE,
THREAD_FACTORY, new ThreadPoolExecutor.DiscardPolicy());
/************************************** 线程池中线程的执行的管理器 ******************************************/
}
...@@ -3,15 +3,9 @@ package com.hl.demo; ...@@ -3,15 +3,9 @@ package com.hl.demo;
import android.app.Application; import android.app.Application;
import android.content.Context; import android.content.Context;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.os.Process;
import android.text.TextUtils;
import com.hoolai.access.open.fastaccess.channel.FastSdk; import com.hoolai.access.open.fastaccess.channel.FastSdk;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
public class GameApplication extends Application { public class GameApplication extends Application {
@Override @Override
...@@ -40,33 +34,4 @@ public class GameApplication extends Application { ...@@ -40,33 +34,4 @@ public class GameApplication extends Application {
super.attachBaseContext(context); super.attachBaseContext(context);
FastSdk.attachBaseContext(this, context); FastSdk.attachBaseContext(this, context);
} }
/**
* 多进程判断,sdk已经做了处理,游戏可不做处理
* @param application
* @return
*/
public static boolean getProcessPerform(Application application){
String processName = getProcessName();
int pid = Process.myPid();
LogUtil.i("my pid:"+pid+",processName:"+processName);
if(!TextUtils.isEmpty(processName) && processName.equals(application.getPackageName())){
return true;
}
return false;
}
public static String getProcessName() {
try {
File file = new File("/proc/" + Process.myPid() + "/" + "cmdline");
BufferedReader mBufferedReader = new BufferedReader(new FileReader(file));
String processName = mBufferedReader.readLine().trim();
mBufferedReader.close();
return processName;
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
} }
package com.hl.demo;
import android.util.Log;
public class LogUtil {
private static final String TAG = "HL_DEMO";
public static void i(String str){
Log.i(TAG, str);
}
}
...@@ -2,193 +2,62 @@ package com.hl.demo; ...@@ -2,193 +2,62 @@ package com.hl.demo;
import android.app.Activity; import android.app.Activity;
import android.app.AlertDialog; import android.app.AlertDialog;
import android.content.Context;
import android.content.Intent; import android.content.Intent;
import android.content.res.Configuration; import android.content.res.Configuration;
import android.content.res.Resources;
import android.os.Bundle; import android.os.Bundle;
import android.text.TextUtils;
import android.view.View; import android.view.View;
import android.widget.ArrayAdapter; import android.widget.Button;
import android.widget.EditText;
import android.widget.ListView;
import android.widget.TextView; import android.widget.TextView;
import android.widget.Toast;
import com.chuanglan.shanyan_sdk.OneKeyLoginManager;
import com.hoolai.access.account.ui.WebviewActivity;
import com.hoolai.access.open.fastaccess.channel.FastSdk; import com.hoolai.access.open.fastaccess.channel.FastSdk;
import com.hoolai.access.open.fastaccess.channel.request.EventType; import com.hoolai.access.open.fastaccess.channel.request.EventType;
import com.hoolai.access.open.fastaccess.channel.request.GoodsInfo;
import com.hoolai.access.open.fastaccess.channel.request.PayParams; import com.hoolai.access.open.fastaccess.channel.request.PayParams;
import com.hoolai.access.open.fastaccess.channel.request.ProductParams;
import com.hoolai.access.open.fastaccess.channel.request.PlayerInfo; import com.hoolai.access.open.fastaccess.channel.request.PlayerInfo;
import com.hoolai.access.open.fastaccess.channel.result.LoginResult; import com.hoolai.access.open.fastaccess.channel.result.LoginResult;
import com.hoolai.access.open.fastaccess.interf.HLAccountListener; import com.hoolai.access.open.fastaccess.interf.HLAccountListener;
import com.hoolai.access.open.fastaccess.interf.HLPaymentListener; import com.hoolai.access.open.fastaccess.interf.HLPaymentListener;
import com.hoolai.access.open.fastaccess.interf.HLProductInfoListener;
import com.hoolai.access.open.fastaccess.interf.HLRealNameListener;
import com.hoolai.access.open.fastaccess.interf.HLSystemListener; import com.hoolai.access.open.fastaccess.interf.HLSystemListener;
import com.hoolai.access.open.fastaccess.utils.Logger; import com.hoolai.access.open.fastaccess.utils.Logger;
import com.hoolai.access.open.fastaccess.utils.ToastUtils; import com.hoolai.access.open.fastaccess.utils.ToastUtils;
import com.hoolai.demo.R;
import java.util.HashMap;
import java.util.List; import java.util.List;
import java.util.Map;
import java.util.UUID;
/** public class MainActivity extends Activity {
* Hoolai_sdk接入说明 private boolean isInit, isLogin;
* 接入文档地址 http://support.hoolai.com/docs/#/android/complete private TextView textview;
*/ private Button initBtn;
public class GameActivity extends Activity { private String str = "";
private TextView contentTv;
private LoginResult userResponse;
private EditText et_tv, et_rpc, et_pwd;
private EditText et_ip_host, et_ip_pwd, et_ip_port;
@Override @Override
protected void onCreate(Bundle savedInstanceState) { protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState); super.onCreate(savedInstanceState);
setContentView(R.layout.activity_example); setContentView(R.layout.activity_main);
textview = findViewById(R.id.textview);
contentTv = findViewById(R.id.main_tv); initBtn = findViewById(R.id.initBtn);
et_tv = findViewById(R.id.et_main);
et_rpc = findViewById(R.id.et_rpc);
et_pwd = findViewById(R.id.et_pwd);
et_ip_host = findViewById(R.id.et_ip_host);
et_ip_port = findViewById(R.id.et_ip_port);
et_ip_pwd = findViewById(R.id.et_ip_pwd);
//hoolai sdk初始化操作
Map<String, String> map = new HashMap<>();
map.put("aa", "bbb");
OneKeyLoginManager.getInstance().setDebug(true);
settingProxy();
}
@Override
protected void onSaveInstanceState(Bundle outState) {
super.onSaveInstanceState(outState);
FastSdk.onSaveInstanceState(outState);
}
@Override
protected void onStart() {
super.onStart();
FastSdk.onStart(this);
}
@Override
protected void onResume() {
super.onResume();
FastSdk.onResume(this);
}
@Override //声明系统回调(初始化,退出,版本升级)监听
protected void onStop() {
super.onStop();
FastSdk.onStop(this);
}
@Override
protected void onPause() {
super.onPause();
FastSdk.onPause(this);
}
@Override
protected void onRestart() {
super.onRestart();
FastSdk.onRestart(this);
}
@Override
protected void onDestroy() {
super.onDestroy();
FastSdk.onDestroy(this);
}
@Override
protected void onNewIntent(Intent intent) {
super.onNewIntent(intent);
FastSdk.onNewIntent(intent);
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
FastSdk.onActivityResult(this, requestCode, resultCode, data);
}
@Override
public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
FastSdk.onRequestPermissionsResult(requestCode, permissions, grantResults);
}
@Override
public void onConfigurationChanged(Configuration newConfig) {
super.onConfigurationChanged(newConfig);
FastSdk.onConfigurationChanged(this, newConfig, getResources());
}
@Override
public void onBackPressed() {
// super.onBackPressed();
//如果游戏需要捕获返回事件,请在这里做逻辑判断调用FastSdk.onBackPressed();
FastSdk.onBackPressed();
exit();
}
/**
* hoolai sdk初始化,必须放到onCreate中,并且在主线程中调用
*/
private void hoolaiSdkInit() {
FastSdk.hlSystemListener = new HLSystemListener() { FastSdk.hlSystemListener = new HLSystemListener() {
@Override @Override
public void onInitSuccess() { public void onInitSuccess() {
runOnUiThread(new Runnable() { isInit = true;
@Override Logger.data("fastsdkdemo","初始化成功");
public void run() { setText(">>初始化成功");
if (!contentTv.getText().toString().contains("登录成功")) { initBtn.setVisibility(View.GONE);
contentTv.setText("初始化成功!\n获取初始化返回配置\n");
}
LogUtil.i("Hoolai sdk初始化成功:");
Toast.makeText(GameActivity.this, "初始化成功!", Toast.LENGTH_SHORT).show();
}
});
} }
@Override @Override
public void onInitFailed(String reason) { public void onInitFailed(String reason) {
runOnUiThread(new Runnable() { Logger.data("fastsdkdemo","初始化失败:"+reason);
@Override setText(">>初始化失败");
public void run() { initBtn.setVisibility(View.VISIBLE);
LogUtil.i("Hoolai sdk初始化失败:" + reason);
Toast.makeText(GameActivity.this,"初始化失败:"+reason,Toast.LENGTH_SHORT).show();
}
});
//sdk初始化失败
//注意初始化未成功不得调用sdk任何接口,游戏可在这里做提示或者重新初始化操作
} }
@Override @Override
public void onCustomExit() { public void onCustomExit() {
Toast.makeText(GameActivity.this, "弹出游戏的退出界面", Toast.LENGTH_SHORT).show(); Logger.data("fastsdkdemo","弹出游戏的退出界面");
/** setText(">>弹出游戏的退出界面");
* demo 只作为参考,游戏应该根据自己所需逻辑实现 new AlertDialog.Builder(MainActivity.this)
* 渠道没有退出二次确认框
* 根据需要加二次确认框
*/
// 渠道不存在退出界面,如百度移动游戏等,此时需在此处弹出游戏退出确认界面,否则会出现渠道审核不通过情况
// 游戏实现自己的退出界面 ,实现退出逻辑,请勿直接照搬demo
// 根据需要加二次确认框
new AlertDialog.Builder(GameActivity.this)
.setTitle("游戏退出弹窗") .setTitle("游戏退出弹窗")
.setMessage("我是游戏的弹窗界面哦") .setMessage("我是游戏的弹窗界面哦")
.setNegativeButton("取消", null) .setNegativeButton("取消", null)
...@@ -212,331 +81,248 @@ public class GameActivity extends Activity { ...@@ -212,331 +81,248 @@ public class GameActivity extends Activity {
@Override @Override
public void onUpdate(String data) { public void onUpdate(String data) {
Logger.data("fastsdkdemo","升级:" + data);
} }
}; };
//声明账号回调监听
FastSdk.hlAccountListener = new HLAccountListener() { FastSdk.hlAccountListener = new HLAccountListener() {
@Override @Override
public void onRefreshUser(LoginResult result) { public void onRefreshUser(LoginResult result) {
LogUtil.i("Hoolai refreshUser:" + result.toString()); //没有小号可忽略
Toast.makeText(GameActivity.this,"小号切换成功"+result.getNickName(),Toast.LENGTH_SHORT).show();
contentTv.setText("用户信息刷新:" + result.toString());
} }
@Override @Override
public void onLoginSuccess(LoginResult result) { public void onLoginSuccess(LoginResult result) {
GameActivity.this.userResponse = result; Logger.data("fastsdkdemo","登录成功:" + result);
contentTv.setText("登录成功:" + result.toString()); setText(">>登录成功" + result.toString() + "");
isLogin = true;
} }
@Override @Override
public void onLoginFailed(String reason) { public void onLoginFailed(String reason) {
LogUtil.i("登录失败:" + reason); Logger.data("fastsdkdemo","登录失败:" + reason);
runOnUiThread(() -> { setText(">>登录失败");
contentTv.setText(reason);
});
} }
@Override @Override
public void onLogout(Object... var1) { public void onLogout(Object... var1) {
contentTv.setText("已登出"); Logger.data("fastsdkdemo","已登出");
setText(">>已登出");
isLogin = false;
} }
}; };
FastSdk.hlPaymentListener = new HLPaymentListener() { FastSdk.hlPaymentListener = new HLPaymentListener() {
@Override @Override
public void onPaySuccess(String result) { public void onPaySuccess(String result) {
Logger.data("fastsdkdemo","支付成功 " + result);
setText(">>支付成功");
} }
@Override @Override
public void onPayFailed(String reason) { public void onPayFailed(String reason) {
Logger.data("fastsdkdemo","支付失败:" + reason);
setText(">>支付失败");
}
@Override
public void onQuerySuccess(List<GoodsInfo> list) {
Logger.data("fastsdkdemo","商品信息获取成功:" + list.toString());
ProductUtils.showProducts(MainActivity.this, list);
setText(">>商品信息获取成功");
} }
}; };
FastSdk.onCreate(this); FastSdk.onCreate(MainActivity.this);
setText("调用初始化");
} }
//=========================以下是模拟游戏调用,都是必接接口======================================== @Override
protected void onSaveInstanceState(Bundle outState) {
/** super.onSaveInstanceState(outState);
* 登录调用,必接 FastSdk.onSaveInstanceState(outState);
*
* @param view
*/
public void onClickLogin(View view) {
FastSdk.login();
}
/**
* 登出,必接
*/
public void onClickInit(View view) {
hoolaiSdkInit();
} }
public void logout(View view) { @Override
FastSdk.logout(); protected void onStart() {
if (userResponse != null) { super.onStart();
} else { FastSdk.onStart(this);
Toast.makeText(GameActivity.this, "请先登录", Toast.LENGTH_SHORT).show();
}
} }
/** @Override
* 海外版sdk需要通过此接口获取商品信息进行UI展示,商品信息会根据区域自动转化币种 protected void onResume() {
* 上国内渠道此接口可不接入,海外版必接 Logger.data("fastsdkdemo","游戏页面onResume");
*/ super.onResume();
public void getPrceInfo(View view) { FastSdk.onResume(this);
if (userResponse == null) {
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show();
return;
} }
if (TextUtils.isEmpty(userResponse.getUid() + "")) { @Override
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show(); protected void onStop() {
return; super.onStop();
FastSdk.onStop(this);
} }
FastSdk.getProductInfo(null, new HLProductInfoListener() {
@Override @Override
public void onQuerySuccess(final List<ProductParams> list) { protected void onPause() {
LogUtil.i("商品信息获取成功:" + list.toString()); super.onPause();
if (list.size() == 0) { FastSdk.onPause(this);
Toast.makeText(GameActivity.this, "商品信息获取为空", Toast.LENGTH_SHORT).show();
return;
}
//游戏获取到商品信息之后可以展示到游戏商品界面
//游戏需要有一套默认的商品信息配置,如果通过此接口获取不到商品信息时使用默认的商品配置
//---------------以下是demo代码-----------------------------------------------
Context context;
AlertDialog.Builder builder = new AlertDialog.Builder(GameActivity.this);
ListView listView = new ListView(GameActivity.this);
listView.setAdapter(new ArrayAdapter(GameActivity.this, android.R.layout.simple_list_item_1, android.R.id.text1, list));
listView.setOnItemClickListener((parent, view1, position, id) -> {
ProductParams payInfo = list.get(position);
// 游戏支付时需要传的参数 示例
PayParams payParams = new PayParams();
payParams.setItemId(payInfo.getItemId());
payParams.setItemName(payInfo.getPriceTag());
payParams.setAmount(Integer.parseInt(payInfo.getPrice()));
payParams.setCount(1);
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams.setCallbackInfo("支付扩展信息,游戏透传参数"+ UUID.randomUUID().toString().replace("-",""));
payParams.addExtendParam("isSupportThirdPayment", "true");//是否支持google之外的三方支付
payParams.addExtendParam("payType", "1");// 1 钱包(默认此类型) 2 点卡,短代类支付,需要通过FastSdk.supportShortterm查询
payParams.addExtendParam("currency", payInfo.getPriceLocal());//币种
FastSdk.pay(GameActivity.this, payParams);
});
builder.setView(listView);
builder.show();
} }
@Override @Override
public void onQueryFailed(String s) { protected void onRestart() {
LogUtil.i("商品信息获取失败:" + s); super.onRestart();
Toast.makeText(GameActivity.this, "商品信息获取失败:" + s, Toast.LENGTH_SHORT).show(); Logger.data("fastsdkdemo","游戏页面onRestart");
} FastSdk.onRestart(this);
});
} }
/** @Override
* 支付调用,必接 protected void onDestroy() {
*/ super.onDestroy();
public void onPay(View view) { FastSdk.onDestroy(this);
pay(1);
} }
@Override
public void customPay(View view) { protected void onNewIntent(Intent intent) {
String amount = String.valueOf(et_tv.getText()); super.onNewIntent(intent);
if (TextUtils.isEmpty(amount)) { FastSdk.onNewIntent(intent);
Toast.makeText(GameActivity.this, "输入金额不能为空", Toast.LENGTH_SHORT).show();
return;
}
pay(Integer.valueOf(amount));
} }
private void pay(int amount) { @Override
if (userResponse == null) { protected void onActivityResult(int requestCode, int resultCode, Intent data) {
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show(); FastSdk.onActivityResult(this, requestCode, resultCode, data);
return;
} }
PayParams payParams = new PayParams(); @Override
payParams.setItemId("aaa.bbb.cc");//商品,要保证游戏内各个商品唯一(可以不传) public void onRequestPermissionsResult(int requestCode, String[] permissions, int[] grantResults) {
//ItemName要求:这些特殊符号都不要有: + % # “ & / ? $ ^ *:) \ < > , |。否则会造成某些渠道支付报错如:华为渠道 super.onRequestPermissionsResult(requestCode, permissions, grantResults);
payParams.setItemName("钻石");//购买物品名称 FastSdk.onRequestPermissionsResult(requestCode, permissions, grantResults);
payParams.setAmount(amount);//金额(分)
payParams.setCount(1);//购买商品数量,例如50元宝,传值50
payParams.setCallbackInfo("callbackInfo");//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams.setCurrency("CNY");//国内可不传或CNY
FastSdk.pay(GameActivity.this, payParams);
//支付服务端回调地址,请在产品信息里配置。
} }
/** @Override
* 退出接口调用,必接 public void onConfigurationChanged(Configuration newConfig) {
*/ super.onConfigurationChanged(newConfig);
public void onExit(View view) { FastSdk.onConfigurationChanged(this, newConfig, getResources());
exit();
} }
public void exit() { @Override
public void onBackPressed() {
setText("调用返回");
FastSdk.exit(); FastSdk.exit();
} }
/** public void init(View v){
* 账号管理,母包没有点击效果,渠道包会展示账号管理界面 setText("调用初始化");
* FastSdk.onCreate(this);
* @param view
*/
public void onClickAccountmanage(View view) { // 管理账号接口
WebviewActivity.start(this);
// if(userResponse==null){
// Toast.makeText(this,"请先登录!",Toast.LENGTH_SHORT).show();
// return ;
// }
}
public void onRealName(View view) {
if (userResponse == null) {
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show();
return;
}
/* *
* activity 游戏activity
* RealNameAuthCallBack 查询回调
* needRealNameAuth 预留字段暂未使用,未实名时是否需要引导玩家实名
*/
FastSdk.getRealNameAuth(new HLRealNameListener() {
/**
* 已实名回调
* @param isAdult 是否成年,部分渠道未提供为null
* @param age 年龄,部分渠道未提供为null
* @param realName 真实姓名,部分渠道未提供为null
*/
@Override
public void onSuccess(Boolean isAdult, Integer age, String realName) {
//游戏根据回调信息进行防沉迷处理
Toast.makeText(GameActivity.this, "已实名,已成年:" + isAdult + ",年龄:" + age + ",姓名:" + realName, Toast.LENGTH_SHORT).show();
} }
/** public void login(View v){
* 未实名或查询异常 if (isInit){
* @param msg 信息 setText("调用登录");
*/ FastSdk.login();
@Override }else{
public void onFail(String msg) { ToastUtils.toast("请先初始化");
//游戏进行防沉迷处理 }
Toast.makeText(GameActivity.this, "实名失败:" + msg, Toast.LENGTH_SHORT).show();
} }
/** public void createRole(View v){
* 渠道不支持查询实名信息 if (isLogin){
*/ setText("创角报送");
@Override FastSdk.report(EventType.CreateRole, getPlayerInfo());
public void notSupport() { }else{
//游戏进行防沉迷处理 ToastUtils.toast("请先登录");
Toast.makeText(GameActivity.this, "渠道不支持实名查询", Toast.LENGTH_SHORT).show();
} }
}, true);
} }
public void enterSever(View v){
/** if (isLogin){
* 数据上报,必接 setText("进服报送");
* FastSdk.report(EventType.EnterServer, getPlayerInfo());
* @param view }else{
*/ ToastUtils.toast("请先登录");
public void createRole(View view) {
if (userResponse == null) {
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show();
return;
} }
Logger.i("上报创角");
sendPlayRoleInfo(EventType.CreateRole);
// sendPlayRoleInfo(EventType.CustomerAction);
} }
public void enterSever(View view) {
if (userResponse == null) { public void levelUp(View v){
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show(); if (isLogin){
return; setText("升级报送");
FastSdk.report(EventType.LevelUp, getPlayerInfo());
}else{
ToastUtils.toast("请先登录");
} }
Logger.i("上报进服");
sendPlayRoleInfo(EventType.EnterServer);
} }
public void levelUp(View view) {
if (userResponse == null) { public void customTrack(View v){
Toast.makeText(this, "请先登录!", Toast.LENGTH_SHORT).show(); if (isLogin){
return; setText("自定义报送");
FastSdk.report(EventType.CustomerAction, getPlayerInfo());
}else{
ToastUtils.toast("请先初始化");
} }
Logger.i("上报升级");
sendPlayRoleInfo(EventType.LevelUp);
} }
private void sendPlayRoleInfo(EventType eventType) { public void logout(View v){
PlayerInfo playerInfo = new PlayerInfo(); if (isLogin){
playerInfo.setRoleId("32424");//角色唯一标识id setText("调用登出");
playerInfo.setRoleName("昵称"); FastSdk.logout();
playerInfo.setRoleLevel("6"); }else{
playerInfo.setZoneId("1"); ToastUtils.toast("请先登录");
playerInfo.setZoneName("华东大区");
playerInfo.setServerId("1区");
playerInfo.setServerName("区名称");
playerInfo.setBalance("66");
playerInfo.setVip("5");
playerInfo.setPartyName("帮派名称");
playerInfo.setClassField("");
playerInfo.setExtendAction("点位名称");
playerInfo.setExtra("a:aaam,b:bbbb");//扩展信息,格式:key:value,key:value
// playerInfo.setAppVersion("");
// playerInfo.setAppResVersion("");
// playerInfo.setRoleCreateTime("");
// playerInfo.setPhylum("");
//对于sdk海外版自定义事件报送,需要在传ACTION的时候做如下处理,中文版可以忽略
//userExtData.put(UserExtDataKeys.ACTION, "oversea_custom");
//userExtData.put(UserExtDataKeys.CUSTOM_KEY,"海外版自定义事件名称");
FastSdk.report(eventType, playerInfo);
} }
public void setProxy(View v) {
settingProxy();
} }
private void settingProxy() { public void getPriceInfo(View v){
String pwd = et_ip_pwd.getText().toString(); if (isLogin){
String host = et_ip_host.getText().toString(); setText("查询商品");
String port = et_ip_port.getText().toString(); FastSdk.queryGoodsInfo();
if (!TextUtils.isEmpty(host) && !TextUtils.isEmpty(pwd) && !TextUtils.isEmpty(port)) { }else{
FastSdk.setProxy(pwd, host, port); ToastUtils.toast("请先登录");
ToastUtils.toast("设置代理:"+host+",pwd:"+pwd+",prot:"+port);
hoolaiSdkInit();
} else {
hoolaiSdkInit();
} }
} }
public void setRpc(View v) { public void doPay(View v){
String pwd = et_pwd.getText().toString(); if (isLogin){
String host = et_rpc.getText().toString(); int amount = 1;//单位:分
if (TextUtils.isEmpty(host) || TextUtils.isEmpty(pwd)) { setText("调用支付");
ToastUtils.toast("ip或密码不可为空"); FastSdk.pay(this, getPayParams(amount));
return; }else{
ToastUtils.toast("请先登录");
} }
//FastSdk.setRpc(pwd, host);
} }
public void onExit(View v){
setText("调用退出");
FastSdk.exit();
}
@Override private PlayerInfo getPlayerInfo(){
public Resources getResources() { PlayerInfo playerInfo = new PlayerInfo();
return FastSdk.getResources(super.getResources()); playerInfo.setRoleId("1235761");//角色唯一标识id
playerInfo.setRoleName("昵称2");
playerInfo.setRoleLevel("11");
playerInfo.setZoneId("100");
playerInfo.setZoneName("华东大区");
playerInfo.setServerId("100");
playerInfo.setServerName("大唐战机");
playerInfo.setBalance("66");
playerInfo.setVip("1");
playerInfo.setPartyName("帮派名称");
playerInfo.setClassField("aaaa");
playerInfo.setExtendAction("aaaatest");
playerInfo.setExtra("a:arm,b:bom");//扩展信息,格式:key:value,key:value
playerInfo.setPhylum("1");
return playerInfo;
}
private PayParams getPayParams(int amount){
PayParams payParams = new PayParams();
payParams.setItemId("aaa.bbb.cc");//商品,要保证游戏内各个商品唯一(可以不传)
//ItemName要求:这些特殊符号都不要有: + % # “ & / ? $ ^ *:) \ < > , |。否则会造成某些渠道支付报错如:华为渠道
payParams.setItemName("钻石");//购买物品名称
payParams.setAmount(amount);//金额(分)
payParams.setCount(1);//购买商品数量,例如50元宝,传值50
payParams.setCallbackInfo("callbackInfo");//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams.setCurrency("CNY");//国内可不传或CNY
return payParams;
}
private void setText(String temp){
str = str + temp + "\n";
textview.setText(str);
} }
} }
\ No newline at end of file
package com.hl.demo;
import android.app.Activity;
import android.app.AlertDialog;
import android.widget.ArrayAdapter;
import android.widget.ListView;
import android.widget.Toast;
import com.hoolai.access.open.fastaccess.channel.FastSdk;
import com.hoolai.access.open.fastaccess.channel.request.GoodsInfo;
import com.hoolai.access.open.fastaccess.channel.request.PayParams;
import java.util.List;
import java.util.UUID;
public class ProductUtils {
public static void showProducts(Activity activity, List<GoodsInfo> list){
if (list.size() == 0) {
Toast.makeText(activity, "商品信息获取为空", Toast.LENGTH_SHORT).show();
return;
}
AlertDialog.Builder builder = new AlertDialog.Builder(activity);
ListView listView = new ListView(activity);
listView.setAdapter(new ArrayAdapter(activity, android.R.layout.simple_list_item_1, android.R.id.text1, list));
listView.setOnItemClickListener((parent, view1, position, id) -> {
GoodsInfo payInfo = list.get(position);
// 游戏支付时需要传的参数 示例
PayParams payParams = new PayParams();
payParams.setItemId(payInfo.getItemId());
payParams.setItemName(payInfo.getItemName());
payParams.setAmount(Integer.parseInt(payInfo.getItemPrice()));
payParams.setCount(Integer.valueOf(payInfo.getItemCount()));
//扩展信息,回调时原样返回,因为各渠道回调参数限制不一致。回调参数暂时只支持长度50。callBackInfo中不要使用这些符号:“|”、“=”、“+”、“/”。
payParams.setCallbackInfo("支付扩展信息,游戏透传参数"+ UUID.randomUUID().toString().replace("-",""));
payParams.addExtendParam("isSupportThirdPayment", "true");//是否支持google之外的三方支付
payParams.addExtendParam("payType", "1");// 1 钱包(默认此类型) 2 点卡,短代类支付,需要通过FastSdk.supportShortterm查询
payParams.addExtendParam("currency", payInfo.getShowTag());//币种
FastSdk.pay(activity, payParams);
});
builder.setView(listView);
builder.show();
}
}
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#aaa"
android:orientation="vertical"
android:paddingTop="@dimen/hl_dp_40">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="2"
android:padding="3dp">
<TextView
android:id="@+id/main_tv"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_marginTop="5dp"
android:padding="5dp"
android:textColor="#333"
android:text="用户信息用户信息用户信息用户信息用户信息用户信"
android:textSize="18sp" />
</ScrollView>
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="3">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_ip_host"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_weight="1"
android:paddingLeft="20dp"
android:text="10.1.67.226"
android:textSize="14dp"
android:hint="ip地址"/>
<EditText
android:id="@+id/et_ip_port"
android:layout_width="80dp"
android:layout_height="48dp"
android:paddingLeft="20dp"
android:text="8888"
android:textSize="14dp"
android:hint="8888"/>
<EditText
android:id="@+id/et_ip_pwd"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_weight="1"
android:inputType="textPassword"
android:paddingLeft="20dp"
android:textSize="14dp"
android:hint="密码"/>
<Button
android:layout_width="80dp"
android:layout_height="48dp"
android:onClick="setProxy"
android:text="设置代理" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<EditText
android:id="@+id/et_rpc"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_weight="1"
android:paddingLeft="20dp"
android:text="10.1.4.172"
android:textSize="14dp"
android:hint="ip地址"/>
<EditText
android:id="@+id/et_pwd"
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_weight="1"
android:inputType="textPassword"
android:paddingLeft="20dp"
android:textSize="14dp"
android:hint="密码"/>
<Button
android:id="@+id/rpcBtn"
android:layout_width="80dp"
android:layout_height="48dp"
android:onClick="setRpc"
android:text="设置rpc" />
</LinearLayout>
<Button
android:id="@+id/init"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="onClickInit"
android:text="初始化" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:id="@+id/fragment"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="onClickLogin"
android:text="登录" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="logout"
android:layout_weight="1"
android:text="登出" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="getPrceInfo"
android:text="商品信息(海外)" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="onPay"
android:text="定额支付" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="customPay"
android:text="自定义支付" />
<EditText
android:id="@+id/et_main"
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:gravity="center"
android:hint="单位分"
android:numeric="integer"
android:textColor="@android:color/holo_red_light"
android:textSize="18sp" />
</LinearLayout>
<Button
android:id="@+id/fragment_accountmanage"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="onClickAccountmanage"
android:text="账号管理" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="onExit"
android:text="退出" />
<Button
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_gravity="center"
android:onClick="onRealName"
android:text="实名" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="createRole"
android:text="创角" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="enterSever"
android:text="进服" />
<Button
android:layout_width="0dp"
android:layout_height="wrap_content"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="levelUp"
android:text="升级" />
</LinearLayout>
</LinearLayout>
</ScrollView>
</LinearLayout>
\ No newline at end of file
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:background="#aaa"
android:orientation="vertical">
<ScrollView
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_weight="1"
android:layout_margin="10dp"
android:padding="20dp"
android:fadeScrollbars="false"
android:background="#eee"
android:fillViewport="true">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="match_parent">
<TextView
android:id="@+id/textview"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:layout_margin="4dp"
android:text="12"
android:textSize="12dp"
android:textColor="#111"/>
</LinearLayout>
</ScrollView>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:orientation="vertical">
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
<Button
android:id="@+id/initBtn"
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:visibility="gone"
android:onClick="init"
android:text="初始化" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="login"
android:text="登录" />
</LinearLayout>
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="createRole"
android:text="创角" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="enterSever"
android:text="进服" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="levelUp"
android:text="升级" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_weight="1"
android:layout_gravity="center"
android:onClick="customTrack"
android:text="自定义" />
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="center"
android:onClick="logout"
android:text="登出" />
<LinearLayout
android:layout_width="match_parent"
android:layout_height="48dp"
android:orientation="horizontal">
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="getPriceInfo"
android:text="商品信息(海外)" />
<Button
android:layout_width="0dp"
android:layout_height="48dp"
android:layout_gravity="center"
android:layout_weight="1"
android:onClick="doPay"
android:text="定额支付" />
</LinearLayout>
<Button
android:layout_width="match_parent"
android:layout_height="48dp"
android:layout_gravity="center"
android:onClick="onExit"
android:text="退出" />
</LinearLayout>
</LinearLayout>
\ No newline at end of file
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment