将jcfw部分代码改为kotlin
This commit is contained in:
parent
b09c735324
commit
ed0f5f42da
2
.idea/kotlinc.xml
generated
2
.idea/kotlinc.xml
generated
@ -1,6 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<project version="4">
|
||||
<component name="KotlinJpsPluginSettings">
|
||||
<option name="version" value="1.8.0-release" />
|
||||
<option name="version" value="1.7.20" />
|
||||
</component>
|
||||
</project>
|
@ -17,7 +17,8 @@
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
|
||||
#ifndef COM_JC_JCFW_CLASS_NAME
|
||||
#define COM_JC_JCFW_CLASS_NAME com_jc_jcfw_JcSDK
|
||||
// Java_com_jc_jcfw_JcSDK_00024Companion_runJS
|
||||
#define COM_JC_JCFW_CLASS_NAME com_jc_jcfw_JcSDK_00024Companion
|
||||
#endif
|
||||
#define JNI_JCFW(FUNC) JNI_METHOD1(COM_JC_JCFW_CLASS_NAME, FUNC)
|
||||
|
||||
@ -259,7 +260,7 @@ extern "C"
|
||||
return result == 0 ? 1 : 0;
|
||||
}
|
||||
#if (CC_TARGET_PLATFORM == CC_PLATFORM_ANDROID)
|
||||
JNIEXPORT jint JNICALL JNI_JCFW(runJS)(JNIEnv *env, jclass clazz, jstring j_fun_id, jstring j_method_name, jobjectArray j_params)
|
||||
JNIEXPORT jint JNICALL JNI_JCFW(runJS)(JNIEnv *env, jobject clazz, jstring j_fun_id, jstring j_method_name, jobjectArray j_params)
|
||||
{
|
||||
if (!_isStarted) {
|
||||
return 0;
|
||||
@ -285,7 +286,7 @@ extern "C"
|
||||
return result == 0 ? 1 : 0;
|
||||
}
|
||||
|
||||
JNIEXPORT jstring JNICALL JNI_JCFW(decryptPass)(JNIEnv *env, jclass clazz, jstring jaccount, jstring jpass)
|
||||
JNIEXPORT jstring JNICALL JNI_JCFW(decryptPass)(JNIEnv *env, jobject clazz, jstring jaccount, jstring jpass)
|
||||
{
|
||||
std::string pass_encrypted = JniHelper::jstring2string(jpass);
|
||||
std::string account = JniHelper::jstring2string(jaccount);
|
||||
@ -293,7 +294,7 @@ extern "C"
|
||||
std::string passDecrypt = decrypt_aes(pass_encrypted, keyStr);
|
||||
return env->NewStringUTF(passDecrypt.c_str());
|
||||
}
|
||||
JNIEXPORT void JNICALL JNI_JCFW(tick)(JNIEnv *env, jclass clazz, jfloat dt)
|
||||
JNIEXPORT void JNICALL JNI_JCFW(tick)(JNIEnv *env, jobject clazz, jfloat dt)
|
||||
{
|
||||
tick2(dt);
|
||||
}
|
||||
@ -352,4 +353,4 @@ bool jsb_register_walletevent_modules(se::Object *global)
|
||||
getOrCreatePlainObject_r("jsb", global, &__jsbObj);
|
||||
__jsbObj->defineFunction("jcCallback", _SE(jsb_wallet_callback));
|
||||
return true;
|
||||
}
|
||||
}
|
@ -7,6 +7,7 @@ plugins {
|
||||
id 'com.google.gms.google-services'
|
||||
// Add the Crashlytics Gradle plugin
|
||||
id 'com.google.firebase.crashlytics'
|
||||
id 'org.jetbrains.kotlin.android'
|
||||
}
|
||||
android {
|
||||
compileSdkVersion PROP_COMPILE_SDK_VERSION.toInteger()
|
||||
|
@ -100,14 +100,14 @@ class MainActivity : UnityPlayerActivity(), Cocos2dxHelperListener {
|
||||
initFacebookSDK()
|
||||
// end of facebook login
|
||||
tiktokOpenApi = TikTokOpenApiFactory.create(this)
|
||||
val payClient = PayClient.getInstance()
|
||||
payClient.init(this)
|
||||
val payClient = PayClient.instance
|
||||
payClient?.init(this)
|
||||
mWalletUtil = WalletUtil(this)
|
||||
}
|
||||
|
||||
override fun onResume() {
|
||||
super.onResume()
|
||||
val paramArr = arrayOf<String>()
|
||||
val paramArr = arrayOfNulls<String>(0)
|
||||
JcSDK.callNativeJS("", "onGameResume", paramArr)
|
||||
}
|
||||
|
||||
@ -483,19 +483,19 @@ class MainActivity : UnityPlayerActivity(), Cocos2dxHelperListener {
|
||||
Log.d(TAG, "need refresh accessToken")
|
||||
mAppAuthSvr!!.refreshToken(funID) {
|
||||
mWalletUtil!!.downloadCfgWithApi(
|
||||
state.accessToken
|
||||
state.accessToken!!
|
||||
) { mWalletUtil!!.passLocal }
|
||||
}
|
||||
} else {
|
||||
Log.d(TAG, "access token no need refresh")
|
||||
mWalletUtil!!.downloadCfgWithApi(state.accessToken) { mWalletUtil!!.passLocal }
|
||||
mWalletUtil!!.downloadCfgWithApi(state.accessToken!!) { mWalletUtil!!.passLocal }
|
||||
}
|
||||
} else {
|
||||
Log.w(TAG, "not login")
|
||||
mExecutor!!.submit {
|
||||
mAppAuthSvr!!.doAuth(funID) {
|
||||
mWalletUtil!!.downloadCfgWithApi(
|
||||
state.accessToken
|
||||
state.accessToken!!
|
||||
) { mWalletUtil!!.passLocal }
|
||||
}
|
||||
}
|
||||
|
@ -109,15 +109,15 @@ class WalletUtil(private val mContext: Context) {
|
||||
fileId = DriveUtils.uploadAppFile(service, file, "application/json")
|
||||
}
|
||||
Log.i(TAG, "File ID: $fileId")
|
||||
func.accept(NativeResult(funID, null, fileId))
|
||||
func.accept(NativeResult(funID!!, null, fileId))
|
||||
successCB(fileId)
|
||||
} catch (e: GoogleJsonResponseException) {
|
||||
Log.i(TAG, "Unable to create file: " + e.details)
|
||||
func.accept(NativeResult(funID, e.message, null))
|
||||
func.accept(NativeResult(funID!!, e.message, null))
|
||||
errorCB("Unable to create file: " + e.message)
|
||||
} catch (e: IOException) {
|
||||
Log.i(TAG, e.message!!)
|
||||
func.accept(NativeResult(funID, e.message, null))
|
||||
func.accept(NativeResult(funID!!, e.message, null))
|
||||
errorCB("Unable to create file: " + e.message)
|
||||
}
|
||||
}
|
||||
@ -155,7 +155,7 @@ class WalletUtil(private val mContext: Context) {
|
||||
}
|
||||
}
|
||||
|
||||
fun downloadCfgWithApi(accessToken: String?, func: Consumer<File?>) {
|
||||
fun downloadCfgWithApi(accessToken: String, func: Consumer<File?>) {
|
||||
val api = DriverApiUtils(accessToken)
|
||||
val fileName = generateFileName(account)
|
||||
val fileLocal = getWalletCfgFile(account)
|
||||
@ -186,7 +186,7 @@ class WalletUtil(private val mContext: Context) {
|
||||
}
|
||||
|
||||
fun uploadCfgWithApi(accessToken: String?, func: Consumer<NativeResult?>) {
|
||||
val api = DriverApiUtils(accessToken)
|
||||
val api = DriverApiUtils(accessToken!!)
|
||||
val fileLocal = getWalletCfgFile(account)
|
||||
try {
|
||||
val fileName = generateFileName(account)
|
||||
@ -197,13 +197,13 @@ class WalletUtil(private val mContext: Context) {
|
||||
fileId = repData.getString("id")
|
||||
}
|
||||
Log.i(TAG, "success upload file with api, ID: $fileId")
|
||||
func.accept(NativeResult(funID, null, fileId))
|
||||
func.accept(NativeResult(funID!!, null, fileId))
|
||||
successCB(fileId)
|
||||
} catch (e: IOException) {
|
||||
func.accept(NativeResult(funID, e.message, null))
|
||||
func.accept(NativeResult(funID!!, e.message, null))
|
||||
errorCB("error upload file with api: " + e.message)
|
||||
} catch (e: JSONException) {
|
||||
func.accept(NativeResult(funID, e.message, null))
|
||||
func.accept(NativeResult(funID!!, e.message, null))
|
||||
errorCB("error upload file with api: " + e.message)
|
||||
}
|
||||
}
|
||||
|
@ -10,6 +10,6 @@ class WalletInterface
|
||||
// sign
|
||||
@JavascriptInterface
|
||||
fun pageCall(dataStr: String?) {
|
||||
EventBus.getDefault().post(WebPageEvent(dataStr))
|
||||
EventBus.getDefault().post(WebPageEvent(dataStr!!))
|
||||
}
|
||||
}
|
@ -1,232 +0,0 @@
|
||||
package com.jc.jcfw;
|
||||
|
||||
import static com.ctf.games.release.Constants.FUNID_PREFIX;
|
||||
|
||||
import android.annotation.SuppressLint;
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.Intent;
|
||||
import android.net.Uri;
|
||||
import android.util.Log;
|
||||
|
||||
import com.ctf.games.release.MainActivity;
|
||||
import com.ctf.games.release.MainApplication;
|
||||
import com.ctf.games.release.ui.UIManager;
|
||||
import com.ctf.games.release.webpage.events.CallJSEvent;
|
||||
import com.ctf.games.release.webpage.events.ProxyCBEvent;
|
||||
import com.google.common.base.Strings;
|
||||
import com.jc.jcfw.google.PayClient;
|
||||
import com.jc.jcfw.util.ThreadUtils;
|
||||
import com.jc.jcfw.util.UIUtils;
|
||||
|
||||
import org.cocos2dx.lib.CocosJSHelper;
|
||||
import org.greenrobot.eventbus.EventBus;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
public class JcSDK {
|
||||
private static final String TAG = JcSDK.class.getSimpleName();
|
||||
private static UnityCallback commonCB;
|
||||
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private static PayClient payClient;
|
||||
|
||||
private static native int runJS(final String funId, final String methodName, final String[] params);
|
||||
|
||||
public static native String decryptPass(final String account, final String pass);
|
||||
|
||||
public static native void tick(float dt);
|
||||
|
||||
public static void initCommonCB(UnityCallback callBack) {
|
||||
Log.i(TAG, "call init common callback from unity");
|
||||
commonCB = callBack;
|
||||
}
|
||||
|
||||
/**
|
||||
* @Deprecated
|
||||
* 不使用该方法, 直接由unity调用cpp方法
|
||||
* @param password
|
||||
*/
|
||||
public static void initWallet(String password) {
|
||||
Log.i(TAG, "call init wallet from unity with password: " + password);
|
||||
CocosJSHelper.initWallet(password);
|
||||
commonCB.nativeCallback("", "wallet init success", 0);
|
||||
}
|
||||
|
||||
/**
|
||||
* 回调至c#
|
||||
*/
|
||||
public static void csCallback(String funId, String msg) {
|
||||
if (!Objects.equals(funId, "") && funId.indexOf("js_") == 0) {
|
||||
commonCB.nativeCallback(funId, msg, 1);
|
||||
} else {
|
||||
commonCB.nativeCallback(funId, msg, 0);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if metamask installed and jump to metamask
|
||||
*
|
||||
* @param url
|
||||
* sample:
|
||||
* "https://metamask.app.link/wc?uri="+ExampleApplication.config.toWCUri();
|
||||
*/
|
||||
|
||||
public static void toWallet(String url) {
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
Log.i(TAG, url);
|
||||
try {
|
||||
intent.setData(Uri.parse(url));
|
||||
MainActivity.app.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
String downloadUrl = "https://metamask.io/download/";
|
||||
if (url.startsWith("imtokenv2")) {
|
||||
downloadUrl = "https://token.im/download";
|
||||
} else if (url.startsWith("okx://")) {
|
||||
downloadUrl = "https://www.okx.com/download";
|
||||
}
|
||||
i.setData(Uri.parse(downloadUrl));
|
||||
MainActivity.app.startActivity(i);
|
||||
}
|
||||
}
|
||||
|
||||
public static void showQRCode(String funid, String content) {
|
||||
UIUtils.showQRCode(MainActivity.app, content, "");
|
||||
}
|
||||
|
||||
public static void showWebPage(String funid, String url) {
|
||||
MainActivity.app.showPage(funid, url);
|
||||
}
|
||||
|
||||
public static void scanQRCode(String funid, String title) {
|
||||
// MainActivity.app.showQRScan(funid, title);
|
||||
UIManager.getSingleton().showQRScan(funid, title);
|
||||
}
|
||||
|
||||
public static void signWithTiktok(String funid) {
|
||||
MainActivity.app.signWithTiktok(funid);
|
||||
}
|
||||
|
||||
public static void signWithFacebook(String funid) {
|
||||
MainActivity.app.signWithFacebook(funid);
|
||||
}
|
||||
|
||||
public static void shareWithFacebook(String content) {
|
||||
MainActivity.app.shareWithFacebook(content);
|
||||
}
|
||||
|
||||
public static void signWithTwitter(String funid) {
|
||||
MainActivity.app.signWithTwitter(funid);
|
||||
}
|
||||
|
||||
public static void signWithGoogle(String funid) {
|
||||
MainActivity.app.signWithGoogle(funid);
|
||||
}
|
||||
|
||||
public static void signWithApple(String funid) {
|
||||
MainActivity.app.signWithApple(funid);
|
||||
}
|
||||
|
||||
public static void signOutGoogle(String funid) {
|
||||
MainActivity.app.signOutGoogle(funid);
|
||||
}
|
||||
|
||||
public static void logEvent(String content) {
|
||||
MainActivity.app.logEvent(content);
|
||||
}
|
||||
|
||||
public static void queryProducts(String funid, String skuListStr) {
|
||||
Log.i(TAG, "queryProducts with: " + skuListStr);
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.getInstance();
|
||||
}
|
||||
List<String> skuList = new ArrayList<>();
|
||||
if (skuListStr.contains(",")) {
|
||||
String[] skuArr = skuListStr.split(",");
|
||||
skuList.addAll(Arrays.asList(skuArr));
|
||||
} else {
|
||||
skuList.add(skuListStr);
|
||||
}
|
||||
payClient.queryProductList(funid, skuList);
|
||||
}
|
||||
|
||||
public static void buyProduct(String funid, String productId, String orderId) {
|
||||
Log.i(TAG, "buyProduct with: " + productId);
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.getInstance();
|
||||
}
|
||||
payClient.buyOne(funid, productId, orderId);
|
||||
}
|
||||
|
||||
public static void queryPurchase(String funid) {
|
||||
Log.i(TAG, "queryPurchase");
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.getInstance();
|
||||
}
|
||||
payClient.queryPurchase(funid);
|
||||
}
|
||||
|
||||
public static void passStorageState(String funid, String account) {
|
||||
Log.i(TAG, "passStorageState with: " + account);
|
||||
MainActivity.app.passStorageState(funid, account);
|
||||
}
|
||||
|
||||
public static void storagePass(String funid, String account, String password) {
|
||||
MainActivity.app.storagePass(funid, account, password);
|
||||
}
|
||||
|
||||
public static void authGetStoragePass(String funid, String account) {
|
||||
MainActivity.app.authGetStoragePass(funid, account);
|
||||
}
|
||||
|
||||
public static void storageGameData(String data) {
|
||||
MainApplication.application.setGameData(data);
|
||||
}
|
||||
|
||||
public static void getClientId(String funid) {
|
||||
Log.i(TAG, "getClientId ");
|
||||
MainActivity.app.getClientId(funid);
|
||||
}
|
||||
|
||||
public static void onProxyCB(String funId, String data) {
|
||||
EventBus.getDefault().post(new ProxyCBEvent(funId, data));
|
||||
}
|
||||
|
||||
public static void nativeCb(String funId, String error, String dataStr) {
|
||||
JSONObject result = new JSONObject();
|
||||
try {
|
||||
if (Strings.isNullOrEmpty(error)) {
|
||||
result.put("errcode", 0);
|
||||
result.put("data", dataStr);
|
||||
} else {
|
||||
result.put("errcode", 1);
|
||||
result.put("errmessage", error);
|
||||
}
|
||||
} catch (JSONException e) {
|
||||
Log.e(TAG, "JSONException: " + e.getMessage());
|
||||
}
|
||||
if (funId == null || funId.isEmpty()) {
|
||||
funId = MainActivity.app.getFunId();
|
||||
}
|
||||
Log.i(TAG, String.format("%s native cb, error: %s, data: %s", funId, error, dataStr));
|
||||
if (funId.startsWith(FUNID_PREFIX)) {
|
||||
EventBus.getDefault().post(new CallJSEvent(funId, result.toString()));
|
||||
} else {
|
||||
String finalFunId = funId;
|
||||
ThreadUtils.runInMain(() -> JcSDK.runJS(finalFunId, "jniCallback", new String[]{result.toString()}));
|
||||
}
|
||||
}
|
||||
|
||||
public static void callNativeJS(String funId, String methodName, String[] params) {
|
||||
ThreadUtils.runInMain(() -> JcSDK.runJS(funId, methodName, params));
|
||||
}
|
||||
|
||||
public static void nativeCb(NativeResult result) {
|
||||
nativeCb(result.getFunid(), result.getError(), result.getDataStr());
|
||||
}
|
||||
}
|
237
app/src/com/jc/jcfw/JcSDK.kt
Normal file
237
app/src/com/jc/jcfw/JcSDK.kt
Normal file
@ -0,0 +1,237 @@
|
||||
package com.jc.jcfw
|
||||
|
||||
import android.annotation.SuppressLint
|
||||
import android.content.ActivityNotFoundException
|
||||
import android.content.Intent
|
||||
import android.net.Uri
|
||||
import android.util.Log
|
||||
import com.ctf.games.release.MainActivity
|
||||
import com.ctf.games.release.MainApplication
|
||||
import com.ctf.games.release.ui.UIManager.Companion.singleton
|
||||
import com.ctf.games.release.webpage.events.CallJSEvent
|
||||
import com.ctf.games.release.webpage.events.ProxyCBEvent
|
||||
import com.google.common.base.Strings
|
||||
import com.jc.jcfw.google.PayClient
|
||||
import com.jc.jcfw.util.ThreadUtils
|
||||
import com.jc.jcfw.util.UIUtils
|
||||
import org.cocos2dx.lib.CocosJSHelper
|
||||
import org.greenrobot.eventbus.EventBus
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.Arrays
|
||||
|
||||
const val FUNID_PREFIX = "webpage_"
|
||||
class JcSDK {
|
||||
companion object {
|
||||
external fun runJS(funId: String?, methodName: String, params: Array<String?>): Int
|
||||
external fun decryptPass(account: String?, pass: String?): String?
|
||||
external fun tick(dt: Float)
|
||||
|
||||
private val TAG = JcSDK::class.java.simpleName
|
||||
private var commonCB: UnityCallback? = null
|
||||
@SuppressLint("StaticFieldLeak")
|
||||
private var payClient: PayClient? = null
|
||||
|
||||
@JvmStatic
|
||||
fun initCommonCB(callBack: UnityCallback?) {
|
||||
Log.i(TAG, "call init common callback from unity")
|
||||
commonCB = callBack
|
||||
}
|
||||
|
||||
/**
|
||||
* @Deprecated
|
||||
* 不使用该方法, 直接由unity调用cpp方法
|
||||
* @param password
|
||||
*/
|
||||
@JvmStatic
|
||||
fun initWallet(password: String) {
|
||||
Log.i(TAG, "call init wallet from unity with password: $password")
|
||||
CocosJSHelper.initWallet(password)
|
||||
commonCB!!.nativeCallback("", "wallet init success", 0)
|
||||
}
|
||||
|
||||
/**
|
||||
* 回调至c#
|
||||
*/
|
||||
@JvmStatic
|
||||
fun csCallback(funId: String, msg: String?) {
|
||||
if (funId != "" && funId.indexOf("js_") == 0) {
|
||||
commonCB!!.nativeCallback(funId, msg, 1)
|
||||
} else {
|
||||
commonCB!!.nativeCallback(funId, msg, 0)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* check if metamask installed and jump to metamask
|
||||
*
|
||||
* @param url
|
||||
* sample:
|
||||
* "https://metamask.app.link/wc?uri="+ExampleApplication.config.toWCUri();
|
||||
*/
|
||||
@JvmStatic
|
||||
fun toWallet(url: String) {
|
||||
val intent = Intent(Intent.ACTION_VIEW)
|
||||
Log.i(TAG, url)
|
||||
try {
|
||||
intent.data = Uri.parse(url)
|
||||
MainActivity.app!!.startActivity(intent)
|
||||
} catch (e: ActivityNotFoundException) {
|
||||
val i = Intent(Intent.ACTION_VIEW)
|
||||
var downloadUrl = "https://metamask.io/download/"
|
||||
if (url.startsWith("imtokenv2")) {
|
||||
downloadUrl = "https://token.im/download"
|
||||
} else if (url.startsWith("okx://")) {
|
||||
downloadUrl = "https://www.okx.com/download"
|
||||
}
|
||||
i.data = Uri.parse(downloadUrl)
|
||||
MainActivity.app!!.startActivity(i)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showQRCode(funid: String?, content: String?) {
|
||||
UIUtils.showQRCode(MainActivity.app, content, "")
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun showWebPage(funid: String?, url: String?) {
|
||||
MainActivity.app!!.showPage(funid, url)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun scanQRCode(funid: String?, title: String?) {
|
||||
// MainActivity.app.showQRScan(funid, title);
|
||||
singleton!!.showQRScan(funid, title)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun signWithTiktok(funid: String?) {
|
||||
MainActivity.app!!.signWithTiktok(funid!!)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun signWithFacebook(funid: String?) {
|
||||
MainActivity.app!!.signWithFacebook(funid!!)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun shareWithFacebook(content: String?) {
|
||||
MainActivity.app!!.shareWithFacebook(content)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun signWithTwitter(funid: String?) {
|
||||
MainActivity.app!!.signWithTwitter(funid!!)
|
||||
}
|
||||
|
||||
@JvmStatic
|
||||
fun signWithGoogle(funid: String?) {
|
||||
MainActivity.app!!.signWithGoogle(funid)
|
||||
}
|
||||
@JvmStatic
|
||||
fun signWithApple(funid: String?) {
|
||||
MainActivity.app!!.signWithApple(funid!!)
|
||||
}
|
||||
@JvmStatic
|
||||
fun signOutGoogle(funid: String?) {
|
||||
MainActivity.app!!.signOutGoogle(funid)
|
||||
}
|
||||
@JvmStatic
|
||||
fun logEvent(content: String?) {
|
||||
MainActivity.app!!.logEvent(content)
|
||||
}
|
||||
@JvmStatic
|
||||
fun queryProducts(funid: String?, skuListStr: String) {
|
||||
Log.i(TAG, "queryProducts with: $skuListStr")
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.instance
|
||||
}
|
||||
val skuList: MutableList<String> = ArrayList()
|
||||
if (skuListStr.contains(",")) {
|
||||
val skuArr = skuListStr.split(",".toRegex()).dropLastWhile { it.isEmpty() }.toTypedArray()
|
||||
skuList.addAll(Arrays.asList(*skuArr))
|
||||
} else {
|
||||
skuList.add(skuListStr)
|
||||
}
|
||||
payClient!!.queryProductList(funid, skuList)
|
||||
}
|
||||
@JvmStatic
|
||||
fun buyProduct(funid: String?, productId: String, orderId: String?) {
|
||||
Log.i(TAG, "buyProduct with: $productId")
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.instance
|
||||
}
|
||||
payClient!!.buyOne(funid, productId, orderId)
|
||||
}
|
||||
@JvmStatic
|
||||
fun queryPurchase(funid: String?) {
|
||||
Log.i(TAG, "queryPurchase")
|
||||
if (payClient == null) {
|
||||
payClient = PayClient.instance
|
||||
}
|
||||
payClient!!.queryPurchase(funid)
|
||||
}
|
||||
@JvmStatic
|
||||
fun passStorageState(funid: String?, account: String) {
|
||||
Log.i(TAG, "passStorageState with: $account")
|
||||
MainActivity.app!!.passStorageState(funid, account)
|
||||
}
|
||||
@JvmStatic
|
||||
fun storagePass(funid: String?, account: String?, password: String?) {
|
||||
MainActivity.app!!.storagePass(funid, account, password)
|
||||
}
|
||||
@JvmStatic
|
||||
fun authGetStoragePass(funid: String?, account: String?) {
|
||||
MainActivity.app!!.authGetStoragePass(funid, account!!)
|
||||
}
|
||||
@JvmStatic
|
||||
fun storageGameData(data: String?) {
|
||||
MainApplication.application!!.gameData = data
|
||||
}
|
||||
@JvmStatic
|
||||
fun getClientId(funid: String?) {
|
||||
Log.i(TAG, "getClientId ")
|
||||
MainActivity.app!!.getClientId(funid)
|
||||
}
|
||||
@JvmStatic
|
||||
fun onProxyCB(funId: String?, data: String?) {
|
||||
EventBus.getDefault().post(ProxyCBEvent(funId!!, data!!))
|
||||
}
|
||||
|
||||
fun nativeCb(funId: String?, error: String?, dataStr: String?) {
|
||||
var funId = funId
|
||||
val result = JSONObject()
|
||||
try {
|
||||
if (Strings.isNullOrEmpty(error)) {
|
||||
result.put("errcode", 0)
|
||||
result.put("data", dataStr)
|
||||
} else {
|
||||
result.put("errcode", 1)
|
||||
result.put("errmessage", error)
|
||||
}
|
||||
} catch (e: JSONException) {
|
||||
Log.e(TAG, "JSONException: " + e.message)
|
||||
}
|
||||
if (funId == null || funId.isEmpty()) {
|
||||
funId = MainActivity.app!!.funId
|
||||
}
|
||||
Log.i(TAG, String.format("%s native cb, error: %s, data: %s", funId, error, dataStr))
|
||||
if (funId != null && funId.startsWith(FUNID_PREFIX)) {
|
||||
EventBus.getDefault().post(CallJSEvent(funId, result.toString()))
|
||||
} else {
|
||||
val finalFunId = funId
|
||||
ThreadUtils.runInMain { runJS(finalFunId, "jniCallback", arrayOf(result.toString())) }
|
||||
}
|
||||
}
|
||||
|
||||
fun callNativeJS(funId: String?, methodName: String, params: Array<String?>) {
|
||||
ThreadUtils.runInMain { runJS(funId, methodName, params) }
|
||||
}
|
||||
|
||||
fun nativeCb(result: NativeResult) {
|
||||
nativeCb(result.funid, result.error, result.dataStr)
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -1,37 +0,0 @@
|
||||
package com.jc.jcfw;
|
||||
|
||||
public class NativeResult {
|
||||
private String funid;
|
||||
private String error;
|
||||
private String dataStr;
|
||||
|
||||
public NativeResult(String funid, String error, String dataStr) {
|
||||
this.funid = funid;
|
||||
this.error = error;
|
||||
this.dataStr = dataStr;
|
||||
}
|
||||
|
||||
public String getFunid() {
|
||||
return funid;
|
||||
}
|
||||
|
||||
public void setFunid(String funid) {
|
||||
this.funid = funid;
|
||||
}
|
||||
|
||||
public String getError() {
|
||||
return error;
|
||||
}
|
||||
|
||||
public void setError(String error) {
|
||||
this.error = error;
|
||||
}
|
||||
|
||||
public String getDataStr() {
|
||||
return dataStr;
|
||||
}
|
||||
|
||||
public void setDataStr(String dataStr) {
|
||||
this.dataStr = dataStr;
|
||||
}
|
||||
}
|
3
app/src/com/jc/jcfw/NativeResult.kt
Normal file
3
app/src/com/jc/jcfw/NativeResult.kt
Normal file
@ -0,0 +1,3 @@
|
||||
package com.jc.jcfw
|
||||
|
||||
class NativeResult(var funid: String, var error: String?, var dataStr: String?)
|
@ -1,5 +0,0 @@
|
||||
package com.jc.jcfw;
|
||||
|
||||
public interface UnityCallback {
|
||||
public void nativeCallback(String funId, String str, int type);
|
||||
}
|
5
app/src/com/jc/jcfw/UnityCallback.kt
Normal file
5
app/src/com/jc/jcfw/UnityCallback.kt
Normal file
@ -0,0 +1,5 @@
|
||||
package com.jc.jcfw
|
||||
|
||||
interface UnityCallback {
|
||||
fun nativeCallback(funId: String?, str: String?, type: Int)
|
||||
}
|
@ -1,251 +0,0 @@
|
||||
package com.jc.jcfw.google;
|
||||
|
||||
import android.app.Activity;
|
||||
import android.content.Context;
|
||||
import android.util.Log;
|
||||
|
||||
import androidx.annotation.NonNull;
|
||||
|
||||
import com.android.billingclient.api.BillingClient;
|
||||
import com.android.billingclient.api.BillingClientStateListener;
|
||||
import com.android.billingclient.api.BillingFlowParams;
|
||||
import com.android.billingclient.api.BillingResult;
|
||||
import com.android.billingclient.api.ProductDetails;
|
||||
import com.android.billingclient.api.Purchase;
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener;
|
||||
import com.android.billingclient.api.QueryProductDetailsParams;
|
||||
import com.android.billingclient.api.QueryPurchasesParams;
|
||||
import com.ctf.games.release.MainActivity;
|
||||
import com.jc.jcfw.JcSDK;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
|
||||
public class PayClient extends Activity implements PurchasesUpdatedListener {
|
||||
private static final String TAG = "GooglePayClient";
|
||||
private static volatile PayClient mInstance = null;
|
||||
private static BillingClient billingClient;
|
||||
private static ConcurrentHashMap<String, ProductDetails> skuDetailsMap;
|
||||
private Context mContext = null;
|
||||
private String mFunId;
|
||||
|
||||
public static PayClient getInstance() {
|
||||
if (null == mInstance) {
|
||||
synchronized (PayClient.class) {
|
||||
if (null == mInstance) {
|
||||
mInstance = new PayClient();
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInstance;
|
||||
}
|
||||
|
||||
public void init(Context context) {
|
||||
this.mContext = context;
|
||||
skuDetailsMap = new ConcurrentHashMap<>();
|
||||
billingClient = BillingClient.newBuilder(context).enablePendingPurchases().setListener(this).build();
|
||||
connectToPlay();
|
||||
}
|
||||
|
||||
private void connectToPlay() {
|
||||
billingClient.startConnection(new BillingClientStateListener() {
|
||||
@Override
|
||||
public void onBillingSetupFinished(@NonNull BillingResult billingResult) {
|
||||
Log.i(TAG, "onBillingSetupFinished, response code: " + billingResult.getResponseCode());
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
Log.i(TAG, "BillingClient is ready");
|
||||
} else {
|
||||
Log.i(TAG, "error init BillingClient with error:: " +billingResult.getResponseCode());
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onBillingServiceDisconnected() {
|
||||
// Try to restart the connection on the next request to
|
||||
// Google Play by calling the startConnection() method.
|
||||
connectToPlay();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
JSONArray handlePurchase(JSONArray dataArr, Purchase purchase) throws JSONException {
|
||||
if (purchase.getPurchaseState() == Purchase.PurchaseState.PURCHASED
|
||||
// || purchase.getPurchaseState() == Purchase.PurchaseState.PENDING
|
||||
) {
|
||||
// Acknowledge purchase and grant the item to the user
|
||||
// Grant entitlement to the user.
|
||||
Log.i(TAG, "handlePurchase:" + purchase.getOriginalJson());
|
||||
Log.i(TAG, "purchase sign:" + purchase.getSignature());
|
||||
if (!purchase.isAcknowledged() && purchase.getProducts().size() > 0) {
|
||||
// consumables 消耗型
|
||||
JSONObject data = new JSONObject();
|
||||
data.put("id", purchase.getProducts().get(0));
|
||||
data.put("token", purchase.getPurchaseToken());
|
||||
dataArr.put(data);
|
||||
}
|
||||
}
|
||||
return dataArr;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPurchasesUpdated(BillingResult billingResult, List<Purchase> purchases) {
|
||||
Log.i(TAG, "onPurchasesUpdated with status: " + billingResult.getResponseCode());
|
||||
if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.OK
|
||||
&& purchases != null) {
|
||||
final JSONArray dataArr = new JSONArray();
|
||||
boolean hasErr = false;
|
||||
for (Purchase purchase : purchases) {
|
||||
try {
|
||||
handlePurchase(dataArr, purchase);
|
||||
} catch (JSONException e) {
|
||||
hasErr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(null,"error parse purchase data", null);
|
||||
} else {
|
||||
purchaseUpdateCb(null,null, dataArr.toString());
|
||||
}
|
||||
} else if (billingResult.getResponseCode() == BillingClient.BillingResponseCode.USER_CANCELED) {
|
||||
purchaseUpdateCb(null,"user cancel buy", null);
|
||||
} else {
|
||||
String errmsg = billingResult.getDebugMessage();
|
||||
if (errmsg.isEmpty()) {
|
||||
errmsg = "other error";
|
||||
}
|
||||
purchaseUpdateCb(null, errmsg, null);
|
||||
}
|
||||
}
|
||||
private void purchaseUpdateCb(String funId, String error, String dataStr) {
|
||||
if (funId == null || funId.isEmpty()) {
|
||||
if (mFunId != null && !mFunId.isEmpty()) {
|
||||
final String _funId = mFunId;
|
||||
runOnUiThread(() -> JcSDK.nativeCb(_funId, error, dataStr));
|
||||
mFunId = null;
|
||||
}
|
||||
} else {
|
||||
runOnUiThread(() -> JcSDK.nativeCb(funId, error, dataStr));
|
||||
}
|
||||
|
||||
}
|
||||
private boolean parseProductDetails(JSONArray dataArr, ProductDetails skuDetails) {
|
||||
JSONObject data = new JSONObject();
|
||||
try {
|
||||
data.put("name", skuDetails.getTitle());
|
||||
data.put("description", skuDetails.getDescription());
|
||||
data.put("id", skuDetails.getProductId());
|
||||
data.put("type", skuDetails.getProductType());
|
||||
if (skuDetails.getProductType().equals(BillingClient.ProductType.INAPP)) {
|
||||
data.put("currencyCode",
|
||||
skuDetails.getOneTimePurchaseOfferDetails().getPriceCurrencyCode());
|
||||
data.put("priceValue", skuDetails.getOneTimePurchaseOfferDetails().getPriceAmountMicros());
|
||||
data.put("priceShow", skuDetails.getOneTimePurchaseOfferDetails().getFormattedPrice());
|
||||
}
|
||||
dataArr.put(data);
|
||||
return true;
|
||||
} catch (JSONException e) {
|
||||
e.printStackTrace();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
public void queryProductList(String funId, List<String> productIds) {
|
||||
List<QueryProductDetailsParams.Product> productList = new ArrayList<>();
|
||||
for (String productId : productIds) {
|
||||
productList.add(
|
||||
QueryProductDetailsParams.Product.newBuilder()
|
||||
.setProductId(productId)
|
||||
.setProductType(BillingClient.ProductType.INAPP)
|
||||
.build());
|
||||
}
|
||||
QueryProductDetailsParams params = QueryProductDetailsParams.newBuilder()
|
||||
.setProductList(productList)
|
||||
.build();
|
||||
billingClient.queryProductDetailsAsync(
|
||||
params,
|
||||
(billingResult, productDetailsList) -> {
|
||||
// Process the result
|
||||
Map<String, ProductDetails> pMap = new HashMap<>();
|
||||
for (ProductDetails details : productDetailsList) {
|
||||
skuDetailsMap.put(details.getProductId(), details);
|
||||
pMap.put(details.getProductId(), details);
|
||||
}
|
||||
final JSONArray dataArr = new JSONArray();
|
||||
boolean hasErr = false;
|
||||
for (Map.Entry<String, ProductDetails> entry : pMap.entrySet()) {
|
||||
ProductDetails skuDetails = entry.getValue();
|
||||
if (!parseProductDetails(dataArr, skuDetails)) {
|
||||
hasErr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(funId, "parse product detail json error", null);
|
||||
} else {
|
||||
purchaseUpdateCb(funId, null, dataArr.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void queryPurchase(String funId) {
|
||||
billingClient.queryPurchasesAsync(
|
||||
QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build(),
|
||||
(billingResult, purchases) -> {
|
||||
// Process the result
|
||||
final JSONArray dataArr = new JSONArray();
|
||||
boolean hasErr = false;
|
||||
for (Purchase purchase : purchases) {
|
||||
try {
|
||||
handlePurchase(dataArr, purchase);
|
||||
} catch (JSONException e) {
|
||||
hasErr = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(funId, "error parse purchase data", null);
|
||||
} else {
|
||||
purchaseUpdateCb(funId, null, dataArr.toString());
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
public void buyOne(String funId, String productId, String orderId) {
|
||||
if (mFunId != null && !mFunId.isEmpty()) {
|
||||
purchaseUpdateCb(funId, "another purchase is in progress", null);
|
||||
return;
|
||||
}
|
||||
if (!skuDetailsMap.containsKey(productId)) {
|
||||
purchaseUpdateCb(funId, "product with : "+productId+ " not found", null);
|
||||
return;
|
||||
}
|
||||
ProductDetails productDetails = skuDetailsMap.get(productId);
|
||||
// Set the parameters for the offer that will be presented
|
||||
// in the billing flow creating separate productDetailsParamsList variable
|
||||
List<BillingFlowParams.ProductDetailsParams> productDetailsParamsList = Collections
|
||||
.singletonList(BillingFlowParams.ProductDetailsParams.newBuilder()
|
||||
.setProductDetails(productDetails)
|
||||
.build());
|
||||
|
||||
BillingFlowParams billingFlowParams = BillingFlowParams.newBuilder()
|
||||
.setProductDetailsParamsList(productDetailsParamsList)
|
||||
.setObfuscatedAccountId(orderId)
|
||||
.setObfuscatedProfileId(orderId)
|
||||
.build();
|
||||
|
||||
// Launch the billing flow
|
||||
this.mFunId = funId;
|
||||
MainActivity.app.runOnUiThread(() -> {
|
||||
billingClient.launchBillingFlow((Activity) mContext, billingFlowParams);
|
||||
});
|
||||
}
|
||||
}
|
250
app/src/com/jc/jcfw/google/PayClient.kt
Normal file
250
app/src/com/jc/jcfw/google/PayClient.kt
Normal file
@ -0,0 +1,250 @@
|
||||
package com.jc.jcfw.google
|
||||
|
||||
import android.app.Activity
|
||||
import android.content.Context
|
||||
import android.util.Log
|
||||
import com.android.billingclient.api.BillingClient
|
||||
import com.android.billingclient.api.BillingClientStateListener
|
||||
import com.android.billingclient.api.BillingFlowParams
|
||||
import com.android.billingclient.api.BillingFlowParams.ProductDetailsParams
|
||||
import com.android.billingclient.api.BillingResult
|
||||
import com.android.billingclient.api.ProductDetails
|
||||
import com.android.billingclient.api.Purchase
|
||||
import com.android.billingclient.api.PurchasesUpdatedListener
|
||||
import com.android.billingclient.api.QueryProductDetailsParams
|
||||
import com.android.billingclient.api.QueryPurchasesParams
|
||||
import com.ctf.games.release.MainActivity
|
||||
import com.jc.jcfw.JcSDK
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class PayClient : Activity(), PurchasesUpdatedListener {
|
||||
private var mContext: Context? = null
|
||||
private var mFunId: String? = null
|
||||
fun init(context: Context?) {
|
||||
mContext = context
|
||||
skuDetailsMap = ConcurrentHashMap()
|
||||
billingClient =
|
||||
BillingClient.newBuilder(context!!).enablePendingPurchases().setListener(this).build()
|
||||
connectToPlay()
|
||||
}
|
||||
|
||||
private fun connectToPlay() {
|
||||
billingClient!!.startConnection(object : BillingClientStateListener {
|
||||
override fun onBillingSetupFinished(billingResult: BillingResult) {
|
||||
Log.i(TAG, "onBillingSetupFinished, response code: " + billingResult.responseCode)
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK) {
|
||||
// The BillingClient is ready. You can query purchases here.
|
||||
Log.i(TAG, "BillingClient is ready")
|
||||
} else {
|
||||
Log.i(TAG, "error init BillingClient with error:: " + billingResult.responseCode)
|
||||
}
|
||||
}
|
||||
|
||||
override fun onBillingServiceDisconnected() {
|
||||
// Try to restart the connection on the next request to
|
||||
// Google Play by calling the startConnection() method.
|
||||
connectToPlay()
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun handlePurchase(dataArr: JSONArray, purchase: Purchase): JSONArray {
|
||||
if (purchase.purchaseState == Purchase.PurchaseState.PURCHASED // || purchase.getPurchaseState() == Purchase.PurchaseState.PENDING
|
||||
) {
|
||||
// Acknowledge purchase and grant the item to the user
|
||||
// Grant entitlement to the user.
|
||||
Log.i(TAG, "handlePurchase:" + purchase.originalJson)
|
||||
Log.i(TAG, "purchase sign:" + purchase.signature)
|
||||
if (!purchase.isAcknowledged && purchase.products.size > 0) {
|
||||
// consumables 消耗型
|
||||
val data = JSONObject()
|
||||
data.put("id", purchase.products[0])
|
||||
data.put("token", purchase.purchaseToken)
|
||||
dataArr.put(data)
|
||||
}
|
||||
}
|
||||
return dataArr
|
||||
}
|
||||
|
||||
override fun onPurchasesUpdated(billingResult: BillingResult, purchases: List<Purchase>?) {
|
||||
Log.i(TAG, "onPurchasesUpdated with status: " + billingResult.responseCode)
|
||||
if (billingResult.responseCode == BillingClient.BillingResponseCode.OK
|
||||
&& purchases != null
|
||||
) {
|
||||
val dataArr = JSONArray()
|
||||
var hasErr = false
|
||||
for (purchase in purchases) {
|
||||
try {
|
||||
handlePurchase(dataArr, purchase)
|
||||
} catch (e: JSONException) {
|
||||
hasErr = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(null, "error parse purchase data", null)
|
||||
} else {
|
||||
purchaseUpdateCb(null, null, dataArr.toString())
|
||||
}
|
||||
} else if (billingResult.responseCode == BillingClient.BillingResponseCode.USER_CANCELED) {
|
||||
purchaseUpdateCb(null, "user cancel buy", null)
|
||||
} else {
|
||||
var errmsg = billingResult.debugMessage
|
||||
if (errmsg.isEmpty()) {
|
||||
errmsg = "other error"
|
||||
}
|
||||
purchaseUpdateCb(null, errmsg, null)
|
||||
}
|
||||
}
|
||||
|
||||
private fun purchaseUpdateCb(funId: String?, error: String?, dataStr: String?) {
|
||||
if (funId == null || funId.isEmpty()) {
|
||||
if (mFunId != null && !mFunId!!.isEmpty()) {
|
||||
runOnUiThread { JcSDK.nativeCb(mFunId, error, dataStr) }
|
||||
mFunId = null
|
||||
}
|
||||
} else {
|
||||
runOnUiThread { JcSDK.nativeCb(funId, error, dataStr) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun parseProductDetails(dataArr: JSONArray, skuDetails: ProductDetails): Boolean {
|
||||
val data = JSONObject()
|
||||
return try {
|
||||
data.put("name", skuDetails.title)
|
||||
data.put("description", skuDetails.description)
|
||||
data.put("id", skuDetails.productId)
|
||||
data.put("type", skuDetails.productType)
|
||||
if (skuDetails.productType == BillingClient.ProductType.INAPP) {
|
||||
data.put(
|
||||
"currencyCode",
|
||||
skuDetails.oneTimePurchaseOfferDetails!!.priceCurrencyCode
|
||||
)
|
||||
data.put("priceValue", skuDetails.oneTimePurchaseOfferDetails!!.priceAmountMicros)
|
||||
data.put("priceShow", skuDetails.oneTimePurchaseOfferDetails!!.formattedPrice)
|
||||
}
|
||||
dataArr.put(data)
|
||||
true
|
||||
} catch (e: JSONException) {
|
||||
e.printStackTrace()
|
||||
false
|
||||
}
|
||||
}
|
||||
|
||||
fun queryProductList(funId: String?, productIds: List<String?>) {
|
||||
val productList: MutableList<QueryProductDetailsParams.Product> = ArrayList()
|
||||
for (productId in productIds) {
|
||||
productList.add(
|
||||
QueryProductDetailsParams.Product.newBuilder()
|
||||
.setProductId(productId!!)
|
||||
.setProductType(BillingClient.ProductType.INAPP)
|
||||
.build()
|
||||
)
|
||||
}
|
||||
val params = QueryProductDetailsParams.newBuilder()
|
||||
.setProductList(productList)
|
||||
.build()
|
||||
billingClient!!.queryProductDetailsAsync(
|
||||
params
|
||||
) { billingResult: BillingResult?, productDetailsList: List<ProductDetails> ->
|
||||
// Process the result
|
||||
val pMap: MutableMap<String, ProductDetails> = HashMap()
|
||||
for (details in productDetailsList) {
|
||||
skuDetailsMap!![details.productId] = details
|
||||
pMap[details.productId] = details
|
||||
}
|
||||
val dataArr = JSONArray()
|
||||
var hasErr = false
|
||||
for ((_, skuDetails) in pMap) {
|
||||
if (!parseProductDetails(dataArr, skuDetails)) {
|
||||
hasErr = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(funId, "parse product detail json error", null)
|
||||
} else {
|
||||
purchaseUpdateCb(funId, null, dataArr.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun queryPurchase(funId: String?) {
|
||||
billingClient!!.queryPurchasesAsync(
|
||||
QueryPurchasesParams.newBuilder().setProductType(BillingClient.ProductType.INAPP).build()
|
||||
) { billingResult: BillingResult?, purchases: List<Purchase> ->
|
||||
// Process the result
|
||||
val dataArr = JSONArray()
|
||||
var hasErr = false
|
||||
for (purchase in purchases) {
|
||||
try {
|
||||
handlePurchase(dataArr, purchase)
|
||||
} catch (e: JSONException) {
|
||||
hasErr = true
|
||||
break
|
||||
}
|
||||
}
|
||||
if (hasErr) {
|
||||
purchaseUpdateCb(funId, "error parse purchase data", null)
|
||||
} else {
|
||||
purchaseUpdateCb(funId, null, dataArr.toString())
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun buyOne(funId: String?, productId: String, orderId: String?) {
|
||||
if (mFunId != null && !mFunId!!.isEmpty()) {
|
||||
purchaseUpdateCb(funId, "another purchase is in progress", null)
|
||||
return
|
||||
}
|
||||
if (!skuDetailsMap!!.containsKey(productId)) {
|
||||
purchaseUpdateCb(funId, "product with : $productId not found", null)
|
||||
return
|
||||
}
|
||||
val productDetails = skuDetailsMap!![productId]
|
||||
// Set the parameters for the offer that will be presented
|
||||
// in the billing flow creating separate productDetailsParamsList variable
|
||||
val productDetailsParamsList = listOf(
|
||||
ProductDetailsParams.newBuilder()
|
||||
.setProductDetails(productDetails!!)
|
||||
.build()
|
||||
)
|
||||
val billingFlowParams = BillingFlowParams.newBuilder()
|
||||
.setProductDetailsParamsList(productDetailsParamsList)
|
||||
.setObfuscatedAccountId(orderId!!)
|
||||
.setObfuscatedProfileId(orderId)
|
||||
.build()
|
||||
|
||||
// Launch the billing flow
|
||||
mFunId = funId
|
||||
MainActivity.app!!.runOnUiThread {
|
||||
billingClient!!.launchBillingFlow(
|
||||
(mContext as Activity?)!!, billingFlowParams
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val TAG = "GooglePayClient"
|
||||
|
||||
@Volatile
|
||||
private var mInstance: PayClient? = null
|
||||
private var billingClient: BillingClient? = null
|
||||
private var skuDetailsMap: ConcurrentHashMap<String, ProductDetails>? = null
|
||||
val instance: PayClient?
|
||||
get() {
|
||||
if (null == mInstance) {
|
||||
synchronized(PayClient::class.java) {
|
||||
if (null == mInstance) {
|
||||
mInstance = PayClient()
|
||||
}
|
||||
}
|
||||
}
|
||||
return mInstance
|
||||
}
|
||||
}
|
||||
}
|
@ -1,101 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.util.Log;
|
||||
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp;
|
||||
import com.google.api.client.extensions.android.json.AndroidJsonFactory;
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
|
||||
import com.google.api.client.http.FileContent;
|
||||
import com.google.api.services.drive.Drive;
|
||||
import com.google.api.services.drive.model.File;
|
||||
import com.google.api.services.drive.model.FileList;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.util.Collections;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class DriveUtils {
|
||||
private static final String TAG = DriveUtils.class.getSimpleName();
|
||||
|
||||
public static Drive generateService(GoogleAccountCredential credential, String appName) {
|
||||
return new Drive.Builder(
|
||||
AndroidHttp.newCompatibleTransport(),
|
||||
AndroidJsonFactory.getDefaultInstance(),
|
||||
credential)
|
||||
.setApplicationName(appName)
|
||||
.build();
|
||||
}
|
||||
|
||||
/**
|
||||
* query app file by filename
|
||||
*
|
||||
* @param service
|
||||
* @param fileName
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String queryOneAppFile(Drive service, String fileName) {
|
||||
boolean querySuccess = false;
|
||||
String fileId = "";
|
||||
while (!querySuccess) {
|
||||
try {
|
||||
FileList files = service.files().list()
|
||||
.setSpaces("appDataFolder")
|
||||
.setFields("nextPageToken, files(id, name)")
|
||||
.setPageSize(100)
|
||||
.execute();
|
||||
querySuccess = true;
|
||||
for (File file : files.getFiles()) {
|
||||
Log.i(TAG, String.format("Found file: %s (%s)\n", file.getName(), file.getId()));
|
||||
if (file.getName().equals(fileName)) {
|
||||
fileId = file.getId();
|
||||
break;
|
||||
}
|
||||
}
|
||||
} catch (IOException e) {
|
||||
Log.i(TAG, "error query file from drive");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
return fileId;
|
||||
}
|
||||
|
||||
/**
|
||||
* download one file from drive
|
||||
*
|
||||
* @param service
|
||||
* @param fileId
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String downloadFile(Drive service, String fileId) throws IOException {
|
||||
OutputStream outputStream = new ByteArrayOutputStream();
|
||||
service.files().get(fileId).executeMediaAndDownloadTo(outputStream);
|
||||
// convert outputStream to JSON string
|
||||
// String json = outputStream.toString();
|
||||
return outputStream.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* upload one file to Drive
|
||||
*
|
||||
* @param service
|
||||
* @param filePath file absolute path
|
||||
* @param fileType application/json
|
||||
* @throws IOException
|
||||
*/
|
||||
public static String uploadAppFile(Drive service, java.io.File filePath, String fileType) throws IOException {
|
||||
String fileName = filePath.getName();
|
||||
File fileMetadata = new File();
|
||||
fileMetadata.setName(fileName);
|
||||
fileMetadata.setParents(Collections.singletonList("appDataFolder"));
|
||||
// "application/json"
|
||||
FileContent mediaContent = new FileContent(fileType, filePath);
|
||||
File file = service.files().create(fileMetadata, mediaContent)
|
||||
.setFields("id")
|
||||
.execute();
|
||||
Log.i(TAG, String.format("%s upload success, File ID: %s", fileName, file.getId()));
|
||||
return file.getId();
|
||||
}
|
||||
}
|
96
app/src/com/jc/jcfw/util/DriveUtils.kt
Normal file
96
app/src/com/jc/jcfw/util/DriveUtils.kt
Normal file
@ -0,0 +1,96 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.util.Log
|
||||
import com.google.api.client.extensions.android.http.AndroidHttp
|
||||
import com.google.api.client.extensions.android.json.AndroidJsonFactory
|
||||
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential
|
||||
import com.google.api.client.http.FileContent
|
||||
import com.google.api.services.drive.Drive
|
||||
import java.io.ByteArrayOutputStream
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
import java.io.OutputStream
|
||||
|
||||
object DriveUtils {
|
||||
private val TAG = DriveUtils::class.java.simpleName
|
||||
fun generateService(credential: GoogleAccountCredential?, appName: String?): Drive {
|
||||
return Drive.Builder(
|
||||
AndroidHttp.newCompatibleTransport(),
|
||||
AndroidJsonFactory.getDefaultInstance(),
|
||||
credential
|
||||
)
|
||||
.setApplicationName(appName)
|
||||
.build()
|
||||
}
|
||||
|
||||
/**
|
||||
* query app file by filename
|
||||
*
|
||||
* @param service
|
||||
* @param fileName
|
||||
* @throws IOException
|
||||
*/
|
||||
fun queryOneAppFile(service: Drive, fileName: String): String {
|
||||
var querySuccess = false
|
||||
var fileId = ""
|
||||
while (!querySuccess) {
|
||||
try {
|
||||
val files = service.files().list()
|
||||
.setSpaces("appDataFolder")
|
||||
.setFields("nextPageToken, files(id, name)")
|
||||
.setPageSize(100)
|
||||
.execute()
|
||||
querySuccess = true
|
||||
for (file in files.files) {
|
||||
Log.i(TAG, String.format("Found file: %s (%s)\n", file.name, file.id))
|
||||
if (file.name == fileName) {
|
||||
fileId = file.id
|
||||
break
|
||||
}
|
||||
}
|
||||
} catch (e: IOException) {
|
||||
Log.i(TAG, "error query file from drive")
|
||||
}
|
||||
}
|
||||
return fileId
|
||||
}
|
||||
|
||||
/**
|
||||
* download one file from drive
|
||||
*
|
||||
* @param service
|
||||
* @param fileId
|
||||
* @throws IOException
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun downloadFile(service: Drive, fileId: String?): String {
|
||||
val outputStream: OutputStream = ByteArrayOutputStream()
|
||||
service.files()[fileId].executeMediaAndDownloadTo(outputStream)
|
||||
// convert outputStream to JSON string
|
||||
// String json = outputStream.toString();
|
||||
return outputStream.toString()
|
||||
}
|
||||
|
||||
/**
|
||||
* upload one file to Drive
|
||||
*
|
||||
* @param service
|
||||
* @param filePath file absolute path
|
||||
* @param fileType application/json
|
||||
* @throws IOException
|
||||
*/
|
||||
@Throws(IOException::class)
|
||||
fun uploadAppFile(service: Drive, filePath: File, fileType: String?): String {
|
||||
val fileName = filePath.name
|
||||
val fileMetadata = com.google.api.services.drive.model.File()
|
||||
fileMetadata.name = fileName
|
||||
fileMetadata.parents = listOf("appDataFolder")
|
||||
// "application/json"
|
||||
val mediaContent = FileContent(fileType, filePath)
|
||||
val file = service.files().create(fileMetadata, mediaContent)
|
||||
.setFields("id")
|
||||
.execute()
|
||||
Log.i(TAG, String.format("%s upload success, File ID: %s", fileName, file.id))
|
||||
return file.id
|
||||
}
|
||||
}
|
@ -1,97 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import org.json.JSONArray;
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.IOException;
|
||||
|
||||
import okhttp3.MediaType;
|
||||
import okhttp3.MultipartBody;
|
||||
import okhttp3.OkHttpClient;
|
||||
import okhttp3.Request;
|
||||
import okhttp3.RequestBody;
|
||||
import okhttp3.Response;
|
||||
|
||||
public class DriverApiUtils {
|
||||
private static final String driveApiBase = "https://www.googleapis.com/drive/v3/files";
|
||||
private static final String driveApiUploadBase = "https://www.googleapis.com/upload/drive/v3/files";
|
||||
private final String TAG = getClass().getSimpleName();
|
||||
|
||||
private String token = "";
|
||||
|
||||
public DriverApiUtils() {
|
||||
}
|
||||
|
||||
public DriverApiUtils(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public String getToken() {
|
||||
return token;
|
||||
}
|
||||
|
||||
public void setToken(String token) {
|
||||
this.token = token;
|
||||
}
|
||||
|
||||
public JSONArray fileList() throws IOException, JSONException {
|
||||
OkHttpClient client = new OkHttpClient().newBuilder()
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(driveApiBase + "?spaces=appDataFolder&fields=files(id, name, modifiedTime)")
|
||||
.get()
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.build();
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
String resStr = response.body().string();
|
||||
JSONObject resJson = new JSONObject(resStr);
|
||||
return resJson.getJSONArray("files");
|
||||
}
|
||||
}
|
||||
|
||||
public String queryOneAppFile(String fileName) throws IOException, JSONException {
|
||||
JSONArray fileList = fileList();
|
||||
for (int i = 0; i < fileList.length(); i++) {
|
||||
JSONObject file = fileList.getJSONObject(i);
|
||||
if (file.getString("name").equals(fileName)) {
|
||||
return file.getString("id");
|
||||
}
|
||||
}
|
||||
return "";
|
||||
}
|
||||
|
||||
public String fileInfo(String fileId) throws IOException {
|
||||
OkHttpClient client = new OkHttpClient().newBuilder()
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(String.format("%s/%s?alt=media", driveApiBase, fileId))
|
||||
.get()
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.build();
|
||||
try (Response response = client.newCall(request).execute()) {
|
||||
return response.body().string();
|
||||
}
|
||||
}
|
||||
|
||||
public String uploadFile(java.io.File filePath, String fileType) throws IOException {
|
||||
OkHttpClient client = new OkHttpClient().newBuilder()
|
||||
.build();
|
||||
String fileName = filePath.getName();
|
||||
String optionStr = "{\"name\":\""+fileName+"\",\"parents\":[\"appDataFolder\"]}";
|
||||
RequestBody body = new MultipartBody.Builder().setType(MultipartBody.FORM)
|
||||
.addFormDataPart("", "upload-options.json",
|
||||
RequestBody.create(optionStr, MediaType.parse("application/json")))
|
||||
.addFormDataPart("", fileName,
|
||||
RequestBody.create(filePath, MediaType.parse("application/octet-stream")))
|
||||
.build();
|
||||
Request request = new Request.Builder()
|
||||
.url(driveApiUploadBase + "?uploadType=multipart")
|
||||
.post(body)
|
||||
.addHeader("Content-Type", fileType)
|
||||
.addHeader("Authorization", "Bearer " + token)
|
||||
.build();
|
||||
Response response = client.newCall(request).execute();
|
||||
return response.body().string();
|
||||
}
|
||||
}
|
98
app/src/com/jc/jcfw/util/DriverApiUtils.kt
Normal file
98
app/src/com/jc/jcfw/util/DriverApiUtils.kt
Normal file
@ -0,0 +1,98 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
|
||||
import okhttp3.MediaType
|
||||
import okhttp3.MediaType.Companion.toMediaTypeOrNull
|
||||
import okhttp3.MultipartBody
|
||||
import okhttp3.OkHttpClient
|
||||
import okhttp3.Request
|
||||
import okhttp3.Request.Builder
|
||||
import okhttp3.RequestBody
|
||||
import okhttp3.RequestBody.Companion.asRequestBody
|
||||
import okhttp3.RequestBody.Companion.toRequestBody
|
||||
import org.json.JSONArray
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
class DriverApiUtils {
|
||||
private val TAG = javaClass.simpleName
|
||||
var token = ""
|
||||
|
||||
constructor() {}
|
||||
constructor(token: String) {
|
||||
this.token = token
|
||||
}
|
||||
|
||||
@Throws(IOException::class, JSONException::class)
|
||||
fun fileList(): JSONArray {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.build()
|
||||
val request: Request = Builder()
|
||||
.url(driveApiBase + "?spaces=appDataFolder&fields=files(id, name, modifiedTime)")
|
||||
.get()
|
||||
.addHeader("Authorization", "Bearer $token")
|
||||
.build()
|
||||
client.newCall(request).execute().use { response ->
|
||||
val resStr = response.body!!.string()
|
||||
val resJson = JSONObject(resStr)
|
||||
return resJson.getJSONArray("files")
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class, JSONException::class)
|
||||
fun queryOneAppFile(fileName: String): String {
|
||||
val fileList = fileList()
|
||||
for (i in 0 until fileList.length()) {
|
||||
val file = fileList.getJSONObject(i)
|
||||
if (file.getString("name") == fileName) {
|
||||
return file.getString("id")
|
||||
}
|
||||
}
|
||||
return ""
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun fileInfo(fileId: String?): String {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.build()
|
||||
val request: Request = Builder()
|
||||
.url(String.format("%s/%s?alt=media", driveApiBase, fileId))
|
||||
.get()
|
||||
.addHeader("Authorization", "Bearer $token")
|
||||
.build()
|
||||
client.newCall(request).execute().use { response -> return response.body!!.string() }
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun uploadFile(filePath: File, fileType: String): String {
|
||||
val client = OkHttpClient().newBuilder()
|
||||
.build()
|
||||
val fileName = filePath.name
|
||||
val optionStr = "{\"name\":\"$fileName\",\"parents\":[\"appDataFolder\"]}"
|
||||
val body: RequestBody = MultipartBody.Builder().setType(MultipartBody.FORM)
|
||||
.addFormDataPart(
|
||||
"", "upload-options.json",
|
||||
optionStr.toRequestBody("application/json".toMediaTypeOrNull())
|
||||
)
|
||||
.addFormDataPart(
|
||||
"", fileName,
|
||||
filePath.asRequestBody("application/octet-stream".toMediaTypeOrNull())
|
||||
)
|
||||
.build()
|
||||
val request: Request = Builder()
|
||||
.url("$driveApiUploadBase?uploadType=multipart")
|
||||
.post(body)
|
||||
.addHeader("Content-Type", fileType)
|
||||
.addHeader("Authorization", "Bearer $token")
|
||||
.build()
|
||||
val response = client.newCall(request).execute()
|
||||
return response.body!!.string()
|
||||
}
|
||||
|
||||
companion object {
|
||||
private const val driveApiBase = "https://www.googleapis.com/drive/v3/files"
|
||||
private const val driveApiUploadBase = "https://www.googleapis.com/upload/drive/v3/files"
|
||||
}
|
||||
}
|
@ -1,240 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.content.ContentResolver;
|
||||
import android.content.ContentUris;
|
||||
import android.content.ContentValues;
|
||||
import android.content.Context;
|
||||
import android.database.Cursor;
|
||||
import android.graphics.Bitmap;
|
||||
import android.graphics.BitmapFactory;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Environment;
|
||||
import android.provider.MediaStore;
|
||||
import android.util.Log;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.OutputStream;
|
||||
import java.io.RandomAccessFile;
|
||||
|
||||
public class FileUtils {
|
||||
private static final String TAG = FileUtils.class.getSimpleName();
|
||||
/**
|
||||
* check if path specificed exists, create it if not exists
|
||||
*
|
||||
* @param fileName path
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
public static boolean fileIsExist(String fileName) {
|
||||
File file = new File(fileName);
|
||||
if (file.exists())
|
||||
return true;
|
||||
else {
|
||||
return file.mkdirs();
|
||||
}
|
||||
}
|
||||
|
||||
public static void writeFile(File filePath, String content) throws IOException {
|
||||
FileOutputStream out = new FileOutputStream(filePath);
|
||||
out.write(content.getBytes());
|
||||
out.close();
|
||||
}
|
||||
|
||||
public static JSONObject readJsonFromFile(File filePath) throws IOException, JSONException {
|
||||
RandomAccessFile f = new RandomAccessFile(filePath, "r");
|
||||
byte[] bytes = new byte[(int) f.length()];
|
||||
f.readFully(bytes);
|
||||
f.close();
|
||||
return new JSONObject(new String(bytes));
|
||||
}
|
||||
|
||||
/**
|
||||
* get image base path of external storage
|
||||
*/
|
||||
public static String getPath(Context context) {
|
||||
String fileName = "";
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
fileName = context.getExternalFilesDir("").getAbsolutePath() + "/current/";
|
||||
} else {
|
||||
if ("Xiaomi".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else if ("HUAWEI".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else if ("HONOR".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else if ("OPPO".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else if ("vivo".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else if ("samsung".equalsIgnoreCase(Build.BRAND)) {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/Camera/";
|
||||
} else {
|
||||
fileName = Environment.getExternalStorageDirectory().getPath() + "/DCIM/";
|
||||
}
|
||||
}
|
||||
File file = new File(fileName);
|
||||
if (file.mkdirs()) {
|
||||
return fileName;
|
||||
}
|
||||
return fileName;
|
||||
}
|
||||
|
||||
public static String insertImageIntoGallery(Context activity, Bitmap source, String filename, String title) {
|
||||
ContentResolver cr = activity.getContentResolver();
|
||||
ContentValues values = new ContentValues();
|
||||
values.put(MediaStore.Images.Media.TITLE, title);
|
||||
values.put(MediaStore.Images.Media.DISPLAY_NAME, title);
|
||||
values.put(MediaStore.Images.Media.DESCRIPTION, title);
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg");
|
||||
// Add the date meta data to ensure the image is added at the front of the gallery
|
||||
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis());
|
||||
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis());
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
values.put(MediaStore.Video.Media.IS_PENDING, 1);
|
||||
}
|
||||
|
||||
Uri url = null;
|
||||
String stringUrl = null; /* value to be returned */
|
||||
|
||||
try {
|
||||
url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values);
|
||||
|
||||
if (source != null) {
|
||||
OutputStream imageOut = cr.openOutputStream(url);
|
||||
try {
|
||||
source.compress(Bitmap.CompressFormat.JPEG, 100, imageOut);
|
||||
} finally {
|
||||
imageOut.close();
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
values.put(MediaStore.Video.Media.IS_PENDING, 0);
|
||||
cr.update(url, values, null, null);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cr.delete(url, null, null);
|
||||
return storeToAlternateSd(activity, source, filename);
|
||||
// url = null;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
if (url != null) {
|
||||
cr.delete(url, null, null);
|
||||
// url = null;
|
||||
}
|
||||
return storeToAlternateSd(activity, source, filename);
|
||||
}
|
||||
if (url != null) {
|
||||
stringUrl = url.toString();
|
||||
}
|
||||
|
||||
return stringUrl;
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have issues saving into our MediaStore, save it directly to our SD card. We can then interact with this file
|
||||
* directly, opposed to pulling from the MediaStore. Again, this is a backup method if things don't work out as we
|
||||
* would expect (seeing as most devices will have a MediaStore).
|
||||
*
|
||||
* @param src
|
||||
* @return - the file's path
|
||||
*/
|
||||
private static String storeToAlternateSd(Context activity, Bitmap src, String filename){
|
||||
if(src == null)
|
||||
return null;
|
||||
|
||||
String sdCardDirectory = getPath(activity);
|
||||
File image = new File(sdCardDirectory, filename + ".jpg");
|
||||
try {
|
||||
FileOutputStream imageOut = new FileOutputStream(image);
|
||||
src.compress(Bitmap.CompressFormat.JPEG, 100, imageOut);
|
||||
imageOut.close();
|
||||
return image.getAbsolutePath();
|
||||
} catch (IOException ex) {
|
||||
ex.printStackTrace();
|
||||
return null;
|
||||
}
|
||||
}
|
||||
/*
|
||||
* save bitmap to system gallery
|
||||
*/
|
||||
public static String saveBitmap(Context activity, String oid, Bitmap bitmap) {
|
||||
String title = "wallet_key_" + oid;
|
||||
String imageName = "wallet_key_" + oid;
|
||||
String uri = insertImageIntoGallery(activity, bitmap, imageName, title);
|
||||
Log.i(TAG, "save image success: " + uri);
|
||||
return uri;
|
||||
}
|
||||
|
||||
|
||||
public static Bitmap loadImgData(Context activity, String oid) {
|
||||
Uri uri = readImageFromGallery(activity, oid);
|
||||
Bitmap data;
|
||||
if (uri != null) {
|
||||
try {
|
||||
data = MediaStore.Images.Media.getBitmap(activity.getContentResolver(),uri);
|
||||
} catch (IOException e) {
|
||||
data = readImageFromExt(activity, oid);
|
||||
}
|
||||
} else {
|
||||
data = readImageFromExt(activity, oid);
|
||||
}
|
||||
|
||||
return data;
|
||||
}
|
||||
|
||||
public static Bitmap readImageFromExt(Context activity, String oid) {
|
||||
String sdCardDirectory = getPath(activity);
|
||||
String imageName = "wallet_key_" + oid;
|
||||
File file = new File(sdCardDirectory, imageName + ".jpg");
|
||||
if (!file.exists()) {
|
||||
return null;
|
||||
}
|
||||
Bitmap bitmap = null;
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeFile(file.getPath());
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
return bitmap;
|
||||
}
|
||||
|
||||
public static Uri readImageFromGallery(Context activity, String oid) {
|
||||
String filename = "wallet_key_" + oid;
|
||||
Uri uri;
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
uri = MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL);
|
||||
} else {
|
||||
uri = MediaStore.Images.Media.EXTERNAL_CONTENT_URI;
|
||||
}
|
||||
Uri result = null;
|
||||
String[] projection = {MediaStore.Images.Media._ID,
|
||||
MediaStore.Images.Media.DATA,
|
||||
MediaStore.Images.Media.DISPLAY_NAME};
|
||||
final String orderBy = MediaStore.Images.Media.DATE_ADDED;
|
||||
Cursor cursor = activity.getContentResolver().query(uri, projection, null, null, orderBy + " DESC");
|
||||
String imageName = "wallet_key_" + oid;
|
||||
if (cursor != null) {
|
||||
int nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME);
|
||||
int idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID);
|
||||
int dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA);
|
||||
while (cursor.moveToNext()) {
|
||||
String name = cursor.getString(nameColumn);
|
||||
long id = cursor.getLong(idColumn);
|
||||
Log.i(TAG, "img name: " + name + " id: " + id);
|
||||
if (name.contains(imageName)) {
|
||||
String data = cursor.getString(dataColumn);
|
||||
result = ContentUris.withAppendedId(MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL), id);
|
||||
Log.i(TAG, "img name: " + name + " id: " + id + " data:" + data);
|
||||
break;
|
||||
}
|
||||
}
|
||||
cursor.close();
|
||||
}
|
||||
return result;
|
||||
}
|
||||
}
|
237
app/src/com/jc/jcfw/util/FileUtils.kt
Normal file
237
app/src/com/jc/jcfw/util/FileUtils.kt
Normal file
@ -0,0 +1,237 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.content.ContentUris
|
||||
import android.content.ContentValues
|
||||
import android.content.Context
|
||||
import android.graphics.Bitmap
|
||||
import android.graphics.BitmapFactory
|
||||
import android.net.Uri
|
||||
import android.os.Build
|
||||
import android.os.Environment
|
||||
import android.provider.MediaStore
|
||||
import android.util.Log
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
import java.io.File
|
||||
import java.io.FileOutputStream
|
||||
import java.io.IOException
|
||||
import java.io.RandomAccessFile
|
||||
|
||||
object FileUtils {
|
||||
private val TAG = FileUtils::class.java.simpleName
|
||||
|
||||
/**
|
||||
* check if path specificed exists, create it if not exists
|
||||
*
|
||||
* @param fileName path
|
||||
* @return TRUE or FALSE
|
||||
*/
|
||||
fun fileIsExist(fileName: String?): Boolean {
|
||||
val file = File(fileName)
|
||||
return if (file.exists()) true else {
|
||||
file.mkdirs()
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class)
|
||||
fun writeFile(filePath: File?, content: String) {
|
||||
val out = FileOutputStream(filePath)
|
||||
out.write(content.toByteArray())
|
||||
out.close()
|
||||
}
|
||||
|
||||
@Throws(IOException::class, JSONException::class)
|
||||
fun readJsonFromFile(filePath: File?): JSONObject {
|
||||
val f = RandomAccessFile(filePath, "r")
|
||||
val bytes = ByteArray(f.length().toInt())
|
||||
f.readFully(bytes)
|
||||
f.close()
|
||||
return JSONObject(String(bytes))
|
||||
}
|
||||
|
||||
/**
|
||||
* get image base path of external storage
|
||||
*/
|
||||
fun getPath(context: Context): String {
|
||||
var fileName = ""
|
||||
fileName = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
context.getExternalFilesDir("")!!.absolutePath + "/current/"
|
||||
} else {
|
||||
if ("Xiaomi".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else if ("HUAWEI".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else if ("HONOR".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else if ("OPPO".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else if ("vivo".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else if ("samsung".equals(Build.BRAND, ignoreCase = true)) {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/Camera/"
|
||||
} else {
|
||||
Environment.getExternalStorageDirectory().path + "/DCIM/"
|
||||
}
|
||||
}
|
||||
val file = File(fileName)
|
||||
return if (file.mkdirs()) {
|
||||
fileName
|
||||
} else fileName
|
||||
}
|
||||
|
||||
fun insertImageIntoGallery(
|
||||
activity: Context,
|
||||
source: Bitmap?,
|
||||
filename: String,
|
||||
title: String?
|
||||
): String? {
|
||||
val cr = activity.contentResolver
|
||||
val values = ContentValues()
|
||||
values.put(MediaStore.Images.Media.TITLE, title)
|
||||
values.put(MediaStore.Images.Media.DISPLAY_NAME, title)
|
||||
values.put(MediaStore.Images.Media.DESCRIPTION, title)
|
||||
values.put(MediaStore.Images.Media.MIME_TYPE, "image/jpeg")
|
||||
// Add the date meta data to ensure the image is added at the front of the gallery
|
||||
values.put(MediaStore.Images.Media.DATE_ADDED, System.currentTimeMillis())
|
||||
values.put(MediaStore.Images.Media.DATE_TAKEN, System.currentTimeMillis())
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
values.put(MediaStore.Video.Media.IS_PENDING, 1)
|
||||
}
|
||||
var url: Uri? = null
|
||||
var stringUrl: String? = null /* value to be returned */
|
||||
try {
|
||||
url = cr.insert(MediaStore.Images.Media.EXTERNAL_CONTENT_URI, values)
|
||||
if (source != null) {
|
||||
val imageOut = cr.openOutputStream(url!!)
|
||||
try {
|
||||
source.compress(Bitmap.CompressFormat.JPEG, 100, imageOut)
|
||||
} finally {
|
||||
imageOut!!.close()
|
||||
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
values.put(MediaStore.Video.Media.IS_PENDING, 0)
|
||||
cr.update(url, values, null, null)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
cr.delete(url!!, null, null)
|
||||
return storeToAlternateSd(activity, source, filename)
|
||||
// url = null;
|
||||
}
|
||||
} catch (e: Exception) {
|
||||
if (url != null) {
|
||||
cr.delete(url, null, null)
|
||||
// url = null;
|
||||
}
|
||||
return storeToAlternateSd(activity, source, filename)
|
||||
}
|
||||
if (url != null) {
|
||||
stringUrl = url.toString()
|
||||
}
|
||||
return stringUrl
|
||||
}
|
||||
|
||||
/**
|
||||
* If we have issues saving into our MediaStore, save it directly to our SD card. We can then interact with this file
|
||||
* directly, opposed to pulling from the MediaStore. Again, this is a backup method if things don't work out as we
|
||||
* would expect (seeing as most devices will have a MediaStore).
|
||||
*
|
||||
* @param src
|
||||
* @return - the file's path
|
||||
*/
|
||||
private fun storeToAlternateSd(activity: Context, src: Bitmap?, filename: String): String? {
|
||||
if (src == null) return null
|
||||
val sdCardDirectory = getPath(activity)
|
||||
val image = File(sdCardDirectory, "$filename.jpg")
|
||||
return try {
|
||||
val imageOut = FileOutputStream(image)
|
||||
src.compress(Bitmap.CompressFormat.JPEG, 100, imageOut)
|
||||
imageOut.close()
|
||||
image.absolutePath
|
||||
} catch (ex: IOException) {
|
||||
ex.printStackTrace()
|
||||
null
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* save bitmap to system gallery
|
||||
*/
|
||||
fun saveBitmap(activity: Context, oid: String, bitmap: Bitmap?): String? {
|
||||
val title = "wallet_key_$oid"
|
||||
val imageName = "wallet_key_$oid"
|
||||
val uri = insertImageIntoGallery(activity, bitmap, imageName, title)
|
||||
Log.i(TAG, "save image success: $uri")
|
||||
return uri
|
||||
}
|
||||
|
||||
fun loadImgData(activity: Context, oid: String): Bitmap? {
|
||||
val uri = readImageFromGallery(activity, oid)
|
||||
val data: Bitmap?
|
||||
data = if (uri != null) {
|
||||
try {
|
||||
MediaStore.Images.Media.getBitmap(activity.contentResolver, uri)
|
||||
} catch (e: IOException) {
|
||||
readImageFromExt(activity, oid)
|
||||
}
|
||||
} else {
|
||||
readImageFromExt(activity, oid)
|
||||
}
|
||||
return data
|
||||
}
|
||||
|
||||
fun readImageFromExt(activity: Context, oid: String): Bitmap? {
|
||||
val sdCardDirectory = getPath(activity)
|
||||
val imageName = "wallet_key_$oid"
|
||||
val file = File(sdCardDirectory, "$imageName.jpg")
|
||||
if (!file.exists()) {
|
||||
return null
|
||||
}
|
||||
var bitmap: Bitmap? = null
|
||||
try {
|
||||
bitmap = BitmapFactory.decodeFile(file.path)
|
||||
} catch (e: Exception) {
|
||||
e.printStackTrace()
|
||||
}
|
||||
return bitmap
|
||||
}
|
||||
|
||||
fun readImageFromGallery(activity: Context, oid: String): Uri? {
|
||||
val filename = "wallet_key_$oid"
|
||||
val uri: Uri
|
||||
uri = if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.Q) {
|
||||
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL)
|
||||
} else {
|
||||
MediaStore.Images.Media.EXTERNAL_CONTENT_URI
|
||||
}
|
||||
var result: Uri? = null
|
||||
val projection = arrayOf(
|
||||
MediaStore.Images.Media._ID,
|
||||
MediaStore.Images.Media.DATA,
|
||||
MediaStore.Images.Media.DISPLAY_NAME
|
||||
)
|
||||
val orderBy = MediaStore.Images.Media.DATE_ADDED
|
||||
val cursor = activity.contentResolver.query(uri, projection, null, null, "$orderBy DESC")
|
||||
val imageName = "wallet_key_$oid"
|
||||
if (cursor != null) {
|
||||
val nameColumn = cursor.getColumnIndex(MediaStore.Images.Media.DISPLAY_NAME)
|
||||
val idColumn = cursor.getColumnIndex(MediaStore.Images.Media._ID)
|
||||
val dataColumn = cursor.getColumnIndex(MediaStore.Images.Media.DATA)
|
||||
while (cursor.moveToNext()) {
|
||||
val name = cursor.getString(nameColumn)
|
||||
val id = cursor.getLong(idColumn)
|
||||
Log.i(TAG, "img name: $name id: $id")
|
||||
if (name.contains(imageName)) {
|
||||
val data = cursor.getString(dataColumn)
|
||||
result = ContentUris.withAppendedId(
|
||||
MediaStore.Images.Media.getContentUri(MediaStore.VOLUME_EXTERNAL),
|
||||
id
|
||||
)
|
||||
Log.i(TAG, "img name: $name id: $id data:$data")
|
||||
break
|
||||
}
|
||||
}
|
||||
cursor.close()
|
||||
}
|
||||
return result
|
||||
}
|
||||
}
|
@ -1,31 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.os.Bundle;
|
||||
|
||||
import org.json.JSONException;
|
||||
import org.json.JSONObject;
|
||||
|
||||
import java.util.Iterator;
|
||||
|
||||
public class JsonUtils {
|
||||
public static Bundle convertJsonToBundle(String jsonString) throws JSONException {
|
||||
Bundle bundle = new Bundle();
|
||||
JSONObject jsonObject = new JSONObject(jsonString);
|
||||
traverseJsonObject(jsonObject, bundle);
|
||||
return bundle;
|
||||
}
|
||||
|
||||
public static void traverseJsonObject(JSONObject jsonObject, Bundle bundle) throws JSONException {
|
||||
Iterator<String> keys = jsonObject.keys();
|
||||
while (keys.hasNext()) {
|
||||
String key = keys.next();
|
||||
Object value = jsonObject.get(key);
|
||||
// if (value instanceof JSONObject) {
|
||||
// traverseJsonObject((JSONObject) value, bundle);
|
||||
// } else {
|
||||
// bundle.putString(key, value.toString());
|
||||
// }
|
||||
bundle.putString(key, value.toString());
|
||||
}
|
||||
}
|
||||
}
|
30
app/src/com/jc/jcfw/util/JsonUtils.kt
Normal file
30
app/src/com/jc/jcfw/util/JsonUtils.kt
Normal file
@ -0,0 +1,30 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.os.Bundle
|
||||
import org.json.JSONException
|
||||
import org.json.JSONObject
|
||||
|
||||
object JsonUtils {
|
||||
@Throws(JSONException::class)
|
||||
fun convertJsonToBundle(jsonString: String?): Bundle {
|
||||
val bundle = Bundle()
|
||||
val jsonObject = JSONObject(jsonString)
|
||||
traverseJsonObject(jsonObject, bundle)
|
||||
return bundle
|
||||
}
|
||||
|
||||
@Throws(JSONException::class)
|
||||
fun traverseJsonObject(jsonObject: JSONObject, bundle: Bundle) {
|
||||
val keys = jsonObject.keys()
|
||||
while (keys.hasNext()) {
|
||||
val key = keys.next()
|
||||
val value = jsonObject[key]
|
||||
// if (value instanceof JSONObject) {
|
||||
// traverseJsonObject((JSONObject) value, bundle);
|
||||
// } else {
|
||||
// bundle.putString(key, value.toString());
|
||||
// }
|
||||
bundle.putString(key, value.toString())
|
||||
}
|
||||
}
|
||||
}
|
@ -1,72 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.content.SharedPreferences;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public class SharedPreferencesHelper {
|
||||
private final SharedPreferences sharedPreferences;
|
||||
private SharedPreferences.Editor editor;
|
||||
|
||||
public SharedPreferencesHelper(Context context, String FILE_NAME) {
|
||||
sharedPreferences = context.getSharedPreferences(FILE_NAME,
|
||||
Context.MODE_PRIVATE);
|
||||
editor = sharedPreferences.edit();
|
||||
}
|
||||
|
||||
public void put(String key, Object object) {
|
||||
if (object instanceof String) {
|
||||
editor.putString(key, (String) object);
|
||||
} else if (object instanceof Integer) {
|
||||
editor.putInt(key, (Integer) object);
|
||||
} else if (object instanceof Boolean) {
|
||||
editor.putBoolean(key, (Boolean) object);
|
||||
} else if (object instanceof Float) {
|
||||
editor.putFloat(key, (Float) object);
|
||||
} else if (object instanceof Long) {
|
||||
editor.putLong(key, (Long) object);
|
||||
} else {
|
||||
editor.putString(key, object.toString());
|
||||
}
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
public Object getSharedPreference(String key, Object defaultObject) {
|
||||
if (defaultObject instanceof String) {
|
||||
return sharedPreferences.getString(key, (String) defaultObject);
|
||||
} else if (defaultObject instanceof Integer) {
|
||||
return sharedPreferences.getInt(key, (Integer) defaultObject);
|
||||
} else if (defaultObject instanceof Boolean) {
|
||||
return sharedPreferences.getBoolean(key, (Boolean) defaultObject);
|
||||
} else if (defaultObject instanceof Float) {
|
||||
return sharedPreferences.getFloat(key, (Float) defaultObject);
|
||||
} else if (defaultObject instanceof Long) {
|
||||
return sharedPreferences.getLong(key, (Long) defaultObject);
|
||||
} else {
|
||||
return sharedPreferences.getString(key, null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void remove(String key) {
|
||||
editor.remove(key);
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
|
||||
public void clear() {
|
||||
editor.clear();
|
||||
editor.commit();
|
||||
}
|
||||
|
||||
|
||||
public Boolean contain(String key) {
|
||||
return sharedPreferences.contains(key);
|
||||
}
|
||||
|
||||
|
||||
public Map<String, ?> getAll() {
|
||||
return sharedPreferences.getAll();
|
||||
}
|
||||
}
|
67
app/src/com/jc/jcfw/util/SharedPreferencesHelper.kt
Normal file
67
app/src/com/jc/jcfw/util/SharedPreferencesHelper.kt
Normal file
@ -0,0 +1,67 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.content.Context
|
||||
import android.content.SharedPreferences
|
||||
|
||||
class SharedPreferencesHelper(context: Context, FILE_NAME: String?) {
|
||||
private val sharedPreferences: SharedPreferences
|
||||
private val editor: SharedPreferences.Editor
|
||||
|
||||
init {
|
||||
sharedPreferences = context.getSharedPreferences(
|
||||
FILE_NAME,
|
||||
Context.MODE_PRIVATE
|
||||
)
|
||||
editor = sharedPreferences.edit()
|
||||
}
|
||||
|
||||
fun put(key: String?, `object`: Any) {
|
||||
if (`object` is String) {
|
||||
editor.putString(key, `object`)
|
||||
} else if (`object` is Int) {
|
||||
editor.putInt(key, `object`)
|
||||
} else if (`object` is Boolean) {
|
||||
editor.putBoolean(key, `object`)
|
||||
} else if (`object` is Float) {
|
||||
editor.putFloat(key, `object`)
|
||||
} else if (`object` is Long) {
|
||||
editor.putLong(key, `object`)
|
||||
} else {
|
||||
editor.putString(key, `object`.toString())
|
||||
}
|
||||
editor.commit()
|
||||
}
|
||||
|
||||
fun getSharedPreference(key: String?, defaultObject: Any?): Any? {
|
||||
return if (defaultObject is String) {
|
||||
sharedPreferences.getString(key, defaultObject as String?)
|
||||
} else if (defaultObject is Int) {
|
||||
sharedPreferences.getInt(key, (defaultObject as Int?)!!)
|
||||
} else if (defaultObject is Boolean) {
|
||||
sharedPreferences.getBoolean(key, (defaultObject as Boolean?)!!)
|
||||
} else if (defaultObject is Float) {
|
||||
sharedPreferences.getFloat(key, (defaultObject as Float?)!!)
|
||||
} else if (defaultObject is Long) {
|
||||
sharedPreferences.getLong(key, (defaultObject as Long?)!!)
|
||||
} else {
|
||||
sharedPreferences.getString(key, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun remove(key: String?) {
|
||||
editor.remove(key)
|
||||
editor.commit()
|
||||
}
|
||||
|
||||
fun clear() {
|
||||
editor.clear()
|
||||
editor.commit()
|
||||
}
|
||||
|
||||
fun contain(key: String?): Boolean {
|
||||
return sharedPreferences.contains(key)
|
||||
}
|
||||
|
||||
val all: Map<String, *>
|
||||
get() = sharedPreferences.all
|
||||
}
|
@ -1,24 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.os.Handler;
|
||||
import android.os.Looper;
|
||||
|
||||
public class ThreadUtils {
|
||||
/**
|
||||
* check if current thread is main thread
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
public static boolean isMainThread() {
|
||||
return Looper.getMainLooper() == Looper.myLooper();
|
||||
}
|
||||
|
||||
public static void runInMain(Runnable action) {
|
||||
if (ThreadUtils.isMainThread()) {
|
||||
action.run();
|
||||
} else {
|
||||
Handler mainHandler = new Handler(Looper.getMainLooper());
|
||||
mainHandler.post(action);
|
||||
}
|
||||
}
|
||||
}
|
23
app/src/com/jc/jcfw/util/ThreadUtils.kt
Normal file
23
app/src/com/jc/jcfw/util/ThreadUtils.kt
Normal file
@ -0,0 +1,23 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.os.Handler
|
||||
import android.os.Looper
|
||||
|
||||
object ThreadUtils {
|
||||
/**
|
||||
* check if current thread is main thread
|
||||
*
|
||||
* @return
|
||||
*/
|
||||
private val isMainThread: Boolean
|
||||
get() = Looper.getMainLooper() == Looper.myLooper()
|
||||
|
||||
fun runInMain(action: Runnable) {
|
||||
if (isMainThread) {
|
||||
action.run()
|
||||
} else {
|
||||
val mainHandler = Handler(Looper.getMainLooper())
|
||||
mainHandler.post(action)
|
||||
}
|
||||
}
|
||||
}
|
@ -1,36 +0,0 @@
|
||||
package com.jc.jcfw.util;
|
||||
|
||||
import android.content.Context;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.MainThread;
|
||||
|
||||
import com.ctf.games.release.dialog.QRCodeActivity;
|
||||
|
||||
public class UIUtils {
|
||||
private static Toast toast;
|
||||
|
||||
@MainThread
|
||||
public static void showToastReal(Context context,String text) {
|
||||
if (toast == null) {
|
||||
toast = Toast.makeText(context, text, Toast.LENGTH_SHORT);
|
||||
} else {
|
||||
toast.setDuration(Toast.LENGTH_SHORT);
|
||||
toast.setText(text);
|
||||
}
|
||||
toast.show();
|
||||
}
|
||||
public static void showToast(Context context, String text) {
|
||||
ThreadUtils.runInMain(() -> showToastReal(context, text));
|
||||
}
|
||||
@MainThread
|
||||
public static void showQRCodeReal(Context context, String str, String title) {
|
||||
QRCodeActivity qrCodeActivity = new QRCodeActivity(context);
|
||||
qrCodeActivity.showQRCode(str, title);
|
||||
qrCodeActivity.show();
|
||||
}
|
||||
|
||||
public static void showQRCode(Context context, String str, String title) {
|
||||
ThreadUtils.runInMain(() -> showQRCodeReal(context, str, title));
|
||||
}
|
||||
}
|
35
app/src/com/jc/jcfw/util/UIUtils.kt
Normal file
35
app/src/com/jc/jcfw/util/UIUtils.kt
Normal file
@ -0,0 +1,35 @@
|
||||
package com.jc.jcfw.util
|
||||
|
||||
import android.content.Context
|
||||
import android.widget.Toast
|
||||
import androidx.annotation.MainThread
|
||||
import com.ctf.games.release.dialog.QRCodeActivity
|
||||
|
||||
object UIUtils {
|
||||
private var toast: Toast? = null
|
||||
@MainThread
|
||||
fun showToastReal(context: Context?, text: String?) {
|
||||
if (toast == null) {
|
||||
toast = Toast.makeText(context, text, Toast.LENGTH_SHORT)
|
||||
} else {
|
||||
toast!!.duration = Toast.LENGTH_SHORT
|
||||
toast!!.setText(text)
|
||||
}
|
||||
toast!!.show()
|
||||
}
|
||||
|
||||
fun showToast(context: Context?, text: String?) {
|
||||
ThreadUtils.runInMain { showToastReal(context, text) }
|
||||
}
|
||||
|
||||
@MainThread
|
||||
fun showQRCodeReal(context: Context?, str: String?, title: String?) {
|
||||
val qrCodeActivity = QRCodeActivity(context!!)
|
||||
qrCodeActivity.showQRCode(str, title)
|
||||
qrCodeActivity.show()
|
||||
}
|
||||
|
||||
fun showQRCode(context: Context?, str: String?, title: String?) {
|
||||
ThreadUtils.runInMain { showQRCodeReal(context, str, title) }
|
||||
}
|
||||
}
|
@ -1,6 +1,7 @@
|
||||
// Top-level build file where you can add configuration options common to all sub-projects/modules.
|
||||
apply from: "config.gradle"
|
||||
buildscript {
|
||||
ext.kotlin_version = '1.7.20'
|
||||
repositories {
|
||||
google()
|
||||
jcenter()
|
||||
@ -15,6 +16,7 @@ buildscript {
|
||||
classpath 'com.google.gms:google-services:4.3.15'
|
||||
|
||||
classpath 'com.google.firebase:firebase-crashlytics-gradle:2.9.6'
|
||||
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1,5 +1,5 @@
|
||||
<resources>
|
||||
<string name="app_name" translatable="false">CEBG</string>
|
||||
<string name="app_name" translatable="false">CF</string>
|
||||
<string name="game_view_content_description" translatable="false">Game view</string>
|
||||
<string name="permission_camera" translatable="false">Scan QRCode need camera permission</string>
|
||||
<string name="qr_code_title" translatable="false">QRCode</string>
|
||||
|
Loading…
x
Reference in New Issue
Block a user