remove js env

This commit is contained in:
CounterFire2023 2024-06-13 17:03:10 +08:00
parent 369659d070
commit ea145e977c
13 changed files with 11 additions and 1878 deletions

1
.idea/gradle.xml generated
View File

@ -12,7 +12,6 @@
<set>
<option value="$PROJECT_DIR$" />
<option value="$PROJECT_DIR$/app" />
<option value="$PROJECT_DIR$/../../crypto/cocos_js/cocos/platform/android/libcocos2dx" />
<option value="$PROJECT_DIR$/../../game/wallet-test/target/android/UnityDataAssetPack" />
<option value="$PROJECT_DIR$/../../game/wallet-test/target/android/unityLibrary" />
</set>

View File

@ -14,10 +14,6 @@
android:extractNativeLibs="true"
android:usesCleartextTraffic="true"
android:theme="@android:style/Theme.NoTitleBar.Fullscreen">
<!-- Tell Cocos2dxActivity the name of our .so -->
<meta-data
android:name="android.app.lib_name"
android:value="cocos2djs" />
<meta-data
android:name="firebase_crashlytics_collection_enabled"
android:value="true" />
@ -32,17 +28,6 @@
android:authorities="com.facebook.app.FacebookContentProvider927390338872834"
android:name="com.facebook.FacebookContentProvider"
android:exported="true" />
<provider
android:name="androidx.core.content.FileProvider"
android:authorities="com.cege.games.release.provider"
android:exported="false"
android:grantUriPermissions="true"
tools:replace="android:authorities">
<meta-data
android:name="android.support.FILE_PROVIDER_PATHS"
android:resource="@xml/app_files"
tools:replace="android:resource" />
</provider>
<activity
android:name=".MainActivity"
@ -104,23 +89,7 @@
</intent-filter>
</activity>
<activity
android:name="com.king.zxing.CaptureActivity"
android:theme="@style/CaptureTheme" />
<activity
android:name=".activity.WebPageActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout"
android:theme="@style/WebViewTheme" />
<activity
android:name=".activity.BiometricActivity"
android:theme="@style/DayNightActivity"
android:screenOrientation="sensorLandscape"
android:configChanges="keyboard|keyboardHidden|orientation|screenLayout|screenSize|layoutDirection"
/>
<activity
android:name=".activity.CustomCaptureActivity"
android:theme="@style/CaptureTheme" />
<!--
This activity declaration is merged with the version from the library manifest.
It demonstrates how an https redirect can be captured, in addition to or instead of
@ -135,71 +104,6 @@
To the list of attributes on the activity element.
-->
<activity
android:exported="true"
android:name="net.openid.appauth.RedirectUriReceiverActivity"
tools:node="replace">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="com.googleusercontent.apps.53206975661-ih3r0ubph3rqejdq97b029difbrk2bqj" />
<data android:scheme="com.googleusercontent.apps.53206975661-asnf3qe4bg29p8h981pgf099osvrjbme" />
</intent-filter>
<intent-filter android:autoVerify="true">
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="http" />
<data android:host="oauth-svr.cebggame.com"/>
<data android:pathPrefix="/google"/>
</intent-filter>
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="https" />
<data android:host="oauth-svr.cebggame.com"/>
<data android:pathPrefix="/google"/>
</intent-filter>
</activity>
<activity
android:name=".tiktokapi.TikTokEntryActivity"
android:launchMode="singleTask"
android:taskAffinity="com.cege.games.release"
android:exported="true" />
<activity
android:name=".oauth.OAuthLoginCbActivity"
tools:node="replace"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="cfoauthcb" android:path="/login_result" />
</intent-filter>
</activity>
<activity
android:name="com.facebook.FacebookActivity"
android:configChanges="keyboard|keyboardHidden|screenLayout|screenSize|orientation"
android:label="@string/app_name" />
<activity
android:name="com.facebook.CustomTabActivity"
android:exported="true">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="@string/fb_login_protocol_scheme" />
</intent-filter>
</activity>
<service
android:name="com.youme.voiceengine.VoiceEngineService"
@ -257,7 +161,6 @@
<uses-permission
android:name="android.permission.WRITE_EXTERNAL_STORAGE"
android:maxSdkVersion="29" />
<uses-permission android:name="android.permission.USE_BIOMETRIC" />
<uses-permission android:name="android.permission.GET_ACCOUNTS" />
<uses-permission android:name="android.permission.AUTHENTICATE_ACCOUNTS" />
<queries>

View File

@ -32,29 +32,6 @@ android {
versionCode 46
versionName "1.0.46"
externalNativeBuild {
ndkBuild {
if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
// skip the NDK Build step if PROP_NDK_MODE is none
targets 'cocos2djs'
arguments 'NDK_TOOLCHAIN_VERSION=clang'
def module_paths = [project.file(rootProject.ext.cfgs.cocos2dxBasePath),
project.file(rootProject.ext.cfgs.cocos2dxBasePath+"/cocos"),
project.file(rootProject.ext.cfgs.cocos2dxBasePath+"/external")]
if (Os.isFamily(Os.FAMILY_WINDOWS)) {
arguments 'NDK_MODULE_PATH=' + module_paths.join(";")
}
else {
arguments 'NDK_MODULE_PATH=' + module_paths.join(':')
}
arguments '-j' + Runtime.runtime.availableProcessors()
abiFilters.addAll(PROP_APP_ABI.split(':').collect{it as String})
}
}
}
manifestPlaceholders = [
'appAuthRedirectScheme': 'com.googleusercontent.apps.53206975661-asnf3qe4bg29p8h981pgf099osvrjbme'
]
@ -69,10 +46,6 @@ android {
externalNativeBuild {
ndkBuild {
if (!project.hasProperty("PROP_NDK_MODE") || PROP_NDK_MODE.compareTo('none') != 0) {
// skip the NDK Build step if PROP_NDK_MODE is none
path "jni/Android.mk"
}
}
}
@ -111,6 +84,8 @@ android {
// This flag must be enabled to see properly-symbolicated native
// stack traces in the Crashlytics dashboard.
nativeSymbolUploadEnabled true
strippedNativeLibsDir 'build/intermediates/stripped_native_libs/release/out/lib'
unstrippedNativeLibsDir 'build/intermediates/merged_native_libs/release/out/lib'
}
}
}
@ -131,24 +106,6 @@ android {
}
}
android.applicationVariants.all { variant ->
// delete previous files first
delete "${buildDir}/intermediates/merged_assets/${variant.dirName}"
variant.mergeAssetsProvider.get().doLast {
def sourceDir = rootProject.ext.cfgs.jsFilePath
copy{
from "${sourceDir}"
include "Data/js/**"
into outputDir
}
copy {
from "${sourceDir}/cert/cacert.pem"
into outputDir
}
}
}
dependencies {
@ -157,8 +114,6 @@ dependencies {
implementation fileTree(dir: 'libs', include: ['*.jar','*.aar'])
implementation project(':unityLibrary')
implementation fileTree(dir: project(':unityLibrary').getProjectDir().toString() + ('\\libs'), include: ['*.jar'])
implementation fileTree(dir: rootProject.ext.cfgs.cocos2dxBasePath + "/cocos/platform/android/java/libs", include: ['*.jar'])
implementation project(':libcocos2dx')
implementation "androidx.appcompat:appcompat:1.0.2"
implementation "androidx.biometric:biometric:1.1.0"

View File

@ -1,115 +1,34 @@
package com.cege.games.release;
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
import static org.cocos2dx.lib.Cocos2dxHelper.getActivity;
import android.content.Intent;
import android.content.pm.ApplicationInfo;
import android.content.pm.PackageManager;
import android.net.Uri;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.os.Message;
import android.util.Log;
import android.view.Window;
import androidx.annotation.NonNull;
import androidx.biometric.BiometricManager;
import com.bytedance.sdk.open.tiktok.TikTokOpenApiFactory;
import com.bytedance.sdk.open.tiktok.api.TikTokOpenApi;
import com.bytedance.sdk.open.tiktok.authorize.model.Authorization;
import com.bytedance.sdk.open.tiktok.base.MediaContent;
import com.bytedance.sdk.open.tiktok.base.VideoObject;
import com.bytedance.sdk.open.tiktok.share.Share;
import com.cege.games.release.activity.WebPageActivity;
import com.cege.games.release.appauth.AppAuthSvr;
import com.cege.games.release.oauth.OAuthUtil;
import com.cege.games.release.ui.UIManager;
import com.cege.games.release.wallet.WalletUtil;
import com.facebook.AccessToken;
import com.facebook.CallbackManager;
import com.facebook.FacebookCallback;
import com.facebook.FacebookException;
import com.facebook.appevents.AppEventsLogger;
import com.facebook.login.LoginManager;
import com.facebook.login.LoginResult;
import com.facebook.share.model.ShareLinkContent;
import com.facebook.share.widget.ShareDialog;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.android.gms.auth.api.signin.GoogleSignInClient;
import com.google.android.gms.auth.api.signin.GoogleSignInOptions;
import com.google.android.gms.common.ConnectionResult;
import com.google.android.gms.common.GoogleApiAvailability;
import com.google.android.gms.common.Scopes;
import com.google.android.gms.common.api.ApiException;
import com.google.android.gms.common.api.Scope;
import com.google.android.gms.tasks.Task;
import com.google.api.services.drive.DriveScopes;
import com.google.firebase.analytics.FirebaseAnalytics;
import com.jc.jcfw.JcSDK;
import com.jc.jcfw.google.PayClient;
import com.jc.jcfw.util.JsonUtils;
import com.unity3d.player.UnityPlayerActivity;
import net.openid.appauth.AuthState;
import org.cocos2dx.lib.Cocos2dxHelper;
import org.cocos2dx.lib.CocosJSHelper;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
public class MainActivity extends UnityPlayerActivity
implements Cocos2dxHelper.Cocos2dxHelperListener {
public class MainActivity extends UnityPlayerActivity {
private static final String TAG = MainActivity.class.getSimpleName();
public static MainActivity app;
// AppAuth
private static final int RC_AUTH = 0X04;
// google sign
private static final int RC_SIGN_IN = 0X05;
// code for request drive to upload
private static final int RC_REQUEST_DRIVE_TO_UPLOAD = 0X051;
// code for request drive to download
private static final int RC_REQUEST_DRIVE_TO_READ = 0X052;
public static final int FILE_SELECTOR_CODE = 0X014;
private String title;
private String mFunID;
// AppAuth
private AppAuthSvr mAppAuthSvr;
private ExecutorService mExecutor;
private TikTokOpenApi tiktokOpenApi;
public String getFunId() {
return mFunID;
}
private GoogleSignInClient mGoogleSignInClient;
// facebook login
private CallbackManager mCallbackManager;
private FirebaseAnalytics mFirebaseAnalytics;
private AppEventsLogger fbLogger;
private WalletUtil mWalletUtil;
private OAuthUtil mOAuthUtil;
public boolean isGooglePlayServicesAvailable() {
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS;
return GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(this) == ConnectionResult.SUCCESS;
}
@Override
@ -120,130 +39,31 @@ public class MainActivity extends UnityPlayerActivity
// Obtain the FirebaseAnalytics instance.
mFirebaseAnalytics = FirebaseAnalytics.getInstance(this);
onLoadNativeLibraries();
app = this;
Cocos2dxHelper.init(this);
CocosJSHelper.initJSEnv(getApplicationContext());
// begin of google sign
// mGoogleSignInClient = initGsiClient();
// end of google sign
// begin of google oauth sign
mAppAuthSvr = new AppAuthSvr(this);
mExecutor = Executors.newSingleThreadExecutor();
mAppAuthSvr.init(mExecutor);
// end of google oauth sign
// begin of facebook login
initFacebookSDK();
// end of facebook login
tiktokOpenApi = TikTokOpenApiFactory.create(this);
PayClient payClient = PayClient.getInstance();
payClient.init(this);
mWalletUtil = new WalletUtil(this);
// JSTimers timer = new JSTimers(Looper.getMainLooper());
// timer.sendEmptyMessage(JSTimers.JS_TICK);
fbLogger = AppEventsLogger.newLogger(this);
}
@Override protected void onResume(){
@Override
protected void onResume() {
super.onResume();
String[] paramArr = new String[0];
JcSDK.callNativeJS("", "onGameResume", paramArr);
}
public static class JSTimers extends Handler {
public static final int JS_TICK = 0;
public JSTimers(@NonNull Looper looper) {
super(looper);
}
@Override
public void handleMessage(Message msg) {
if (msg.what == JS_TICK) {
JcSDK.tick(0.033f);
sendEmptyMessageDelayed(JS_TICK, 33);
} else {
removeMessages(JS_TICK);
}
}
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
super.onActivityResult(requestCode, resultCode, data);
mCallbackManager.onActivityResult(requestCode, resultCode, data);
UIManager.getSingleton().onActivityResult(this, requestCode, resultCode, data);
if (resultCode == RESULT_OK && data != null) {
switch (requestCode) {
case RC_AUTH:
mAppAuthSvr.parseLoginResult(data);
break;
case RC_SIGN_IN:
handleSignInResult(GoogleSignIn.getSignedInAccountFromIntent(data));
break;
case FILE_SELECTOR_CODE:
shareToTikTok(mFunID, data.getData());
break;
case RC_REQUEST_DRIVE_TO_UPLOAD:
mExecutor.submit(() -> mWalletUtil.uploadCfgWithGPS(_result -> {}));
break;
case RC_REQUEST_DRIVE_TO_READ:
mExecutor.submit(() -> mWalletUtil.downloadCfgWithGPS(_file -> mWalletUtil.getPassLocal()));
break;
}
} else {
if (requestCode == RC_REQUEST_DRIVE_TO_UPLOAD || requestCode == RC_REQUEST_DRIVE_TO_READ) {
mWalletUtil.errorCB("activity result with code: " + resultCode);
}
if (requestCode == RC_SIGN_IN) {
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(data);
handleSignInResult(task);
}
mFunID = "";
}
}
@Override
protected void onStart() {
super.onStart();
UIManager.getSingleton().onStartActivity(this);
if (mExecutor.isShutdown()) {
mExecutor = Executors.newSingleThreadExecutor();
}
}
// begin for unity
protected void onLoadNativeLibraries() {
try {
ApplicationInfo ai = getPackageManager().getApplicationInfo(getPackageName(), PackageManager.GET_META_DATA);
Bundle bundle = ai.metaData;
String libName = bundle.getString("android.app.lib_name");
System.loadLibrary(libName);
} catch (Throwable e) {
e.printStackTrace();
}
}
@Override
public void showDialog(String pTitle, String pMessage) {
}
@Override
public void runOnGLThread(Runnable pRunnable) {
}
private GoogleSignInClient initGsiClient() {
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestScopes(new Scope(Scopes.EMAIL))
.requestIdToken(getString(R.string.default_web_client_id1))
.build();
return GoogleSignIn.getClient(this, gso);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
@ -253,153 +73,6 @@ public class MainActivity extends UnityPlayerActivity
}
public void signWithGoogle(String funId) {
this.mFunID = funId;
if (isGooglePlayServicesAvailable()) {
if (mGoogleSignInClient == null) {
mGoogleSignInClient = initGsiClient();
}
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account != null) {
Log.w(TAG, "already login: " + account.getIdToken());
mGoogleSignInClient.silentSignIn()
.addOnCompleteListener(this, this::handleSignInResult);
} else {
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, RC_SIGN_IN);
}
} else {
Log.d(TAG, "no gms, use app auth");
AuthState state = mAppAuthSvr.getCurrentState();
if (state.isAuthorized()) {
if (state.getNeedsTokenRefresh()) {
Log.w(TAG, "need refresh accessToken");
mAppAuthSvr.refreshToken(funId, null);
} else {
Log.w(TAG, "already login, accessToken not expired, id token:: " + state.getIdToken());
JcSDK.nativeCb(this.mFunID, null, state.getIdToken());
}
} else {
Log.w(TAG, "not login");
mExecutor.submit(() -> mAppAuthSvr.doAuth(funId, null));
}
}
}
public void signOutGoogle(String funId) {
if (isGooglePlayServicesAvailable()) {
if (mGoogleSignInClient != null) {
mGoogleSignInClient.signOut()
.addOnCompleteListener(this, task -> {
// ...
});
}
}
}
private void handleSignInResult(Task<GoogleSignInAccount> completedTask) {
try {
GoogleSignInAccount account = completedTask.getResult(ApiException.class);
Log.w(TAG, "gso signIn success: " + account.getIdToken());
JcSDK.nativeCb(this.mFunID, null, account.getIdToken());
// Signed in successfully, show authenticated UI.
} catch (ApiException e) {
// The ApiException status code indicates the detailed failure reason.
// Please refer to the GoogleSignInStatusCodes class reference for more
// information.
Log.w(TAG, "signInResult:failed code=" + e.getStatusCode());
JcSDK.nativeCb(this.mFunID, "signInResult:failed code=" + e.getStatusCode(), null);
}
}
// sign with tiktok
public void signWithTiktok(String funId) {
this.mFunID = funId;
Log.i(TAG, "login with tiktok: " + funId);
// STEP 1: Create an instance of TiktokOpenApi
// STEP 2: Create an instance of Authorization.Request and set parameters
Authorization.Request request = new Authorization.Request();
request.scope = "user.info.basic,video.list";
request.state = funId;
tiktokOpenApi.authorize(request);
}
// begin of facebook login
private void initFacebookSDK() {
mCallbackManager = CallbackManager.Factory.create();
fbLogger = AppEventsLogger.newLogger(this);
LoginManager.getInstance().registerCallback(mCallbackManager,
new FacebookCallback<LoginResult>() {
@Override
public void onSuccess(LoginResult loginResult) {
AccessToken accessToken = AccessToken.getCurrentAccessToken();
Log.d(TAG, "Login Success:: accessToken: " + accessToken.getToken());
if (!verifyFbAccessToken(accessToken)) {
JcSDK.nativeCb(MainActivity.app.mFunID, "access token expired", null);
}
}
@Override
public void onCancel() {
Log.d(TAG, "Login cancel");
JcSDK.nativeCb(MainActivity.app.mFunID, "user login cancel", null);
}
@Override
public void onError(FacebookException exception) {
Log.i(TAG, "Login error: " + exception.getMessage());
JcSDK.nativeCb(MainActivity.app.mFunID, exception.getMessage(), null);
}
});
}
public void signWithFacebook(String funId) {
Log.i(TAG, "login with facebook: " + funId);
this.mFunID = funId;
AccessToken accessToken = AccessToken.getCurrentAccessToken();
if (!verifyFbAccessToken(accessToken)) {
LoginManager.getInstance().logInWithReadPermissions(this, Arrays.asList("public_profile", "email"));
}
}
public void shareWithFacebook(String content) {
ShareLinkContent linkContent = new ShareLinkContent.Builder()
.setContentUrl(Uri.parse("https://www.google.com"))
.setQuote(content)
.build();
ShareDialog.show(this, linkContent);
}
private boolean verifyFbAccessToken(AccessToken accessToken) {
boolean isLoggedIn = accessToken != null && !accessToken.isExpired();
if (isLoggedIn) {
JcSDK.nativeCb(this.mFunID, null, accessToken.getToken());
return true;
} else {
return false;
}
}
// end of facebook login
public void signWithTwitter(String funId) {
Log.i(TAG, "login with twitter: " + funId);
this.mFunID = funId;
}
public void oauthLogin(String funId, String jsonData) {
if (this.mOAuthUtil == null) {
this.mOAuthUtil = new OAuthUtil(this);
}
try {
this.mOAuthUtil.startLogin(funId, jsonData);
} catch (JSONException e) {
JcSDK.nativeCb(funId, e.getMessage(), null);
}
}
public void logEvent(String content) {
try {
Bundle bundle = JsonUtils.convertJsonToBundle(content);
@ -413,165 +86,4 @@ public class MainActivity extends UnityPlayerActivity
}
}
public void showPage(String fid, final String url) {
runOnUiThread(() -> {
Intent intent = new Intent(this, WebPageActivity.class);
intent.putExtra("url", url);
startActivity(intent);
});
}
public void shareToTikTok(String funId, Uri uriToImage) {
this.mFunID = funId;
grantUriPermission("com.zhiliaoapp.musically",
uriToImage, Intent.FLAG_GRANT_READ_URI_PERMISSION);
grantUriPermission("com.ss.android.ugc.trill",
uriToImage, Intent.FLAG_GRANT_READ_URI_PERMISSION);
Log.i(TAG, "share to tiktok: " + uriToImage.toString());
if (tiktokOpenApi.isShareSupportFileProvider()) {
Share.Request request = new Share.Request();
ArrayList<String> mUri = new ArrayList<>();
mUri.add(uriToImage.toString());
VideoObject videoObject = new VideoObject();
videoObject.mVideoPaths = mUri;
MediaContent content = new MediaContent();
content.mMediaObject = videoObject;
// 3.set required parameters
request.mMediaContent = content;
request.mState = funId;
request.mShareFormat = Share.Format.DEFAULT;
tiktokOpenApi.share(request);
}
// share with Android ShareSheet
// runOnUiThread(() -> {
// Log.i(TAG, "share to tiktok: " + uriToImage);
// Intent shareIntent = new Intent();
// shareIntent.setAction(Intent.ACTION_SEND);
// shareIntent.putExtra(Intent.EXTRA_STREAM, uriToImage);
// shareIntent.setType("video/*");
// startActivity(Intent.createChooser(shareIntent, "share"));
// });
}
private void openFileSelector() {
Intent intent = new Intent(Intent.ACTION_GET_CONTENT);
intent.setType("video/*");
intent.addCategory(Intent.CATEGORY_OPENABLE);
startActivityForResult(intent, FILE_SELECTOR_CODE);
}
public void passStorageState(String funID, String account) {
Log.i(TAG, "passStorageState with: " + account);
int touchIDState = BiometricManager.from(this)
.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS ? 1 : 0;
JSONObject result = new JSONObject();
try {
result.put("biometrics", touchIDState);
JcSDK.nativeCb(funID, null, result.toString());
} catch (JSONException e) {
JcSDK.nativeCb(funID, "JSON error", null);
}
}
private void loginAndRequestDrivePermission(int requestCode) {
Log.i(TAG, "no drive permission");
GoogleSignInOptions gso = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
.requestIdToken(getString(R.string.default_web_client_id1))
.requestScopes(new Scope(Scopes.EMAIL), new Scope(DriveScopes.DRIVE_APPDATA))
.build();
mGoogleSignInClient = GoogleSignIn.getClient(this, gso);
Intent signInIntent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(signInIntent, requestCode);
}
public void storagePass(String funID, String account, String password) {
Log.i(TAG, String.format("storagePass with: %s | %s", funID, account));
this.mFunID = funID;
mWalletUtil.updateParams(funID, account);
mWalletUtil.savePassToLocal(password, _file -> {
if (isGooglePlayServicesAvailable()) {
if (!GoogleSignIn.hasPermissions(
GoogleSignIn.getLastSignedInAccount(getActivity()),
new Scope(DriveScopes.DRIVE_APPDATA))) {
loginAndRequestDrivePermission(RC_REQUEST_DRIVE_TO_UPLOAD);
} else {
Log.i(TAG, "had drive permission");
mWalletUtil.uploadCfgWithGPS(_result -> {});
}
} else {
AuthState state = mAppAuthSvr.getCurrentState();
if (state.isAuthorized()) {
if (state.getNeedsTokenRefresh()) {
Log.d(TAG, "need refresh accessToken");
mAppAuthSvr.refreshToken(funID, _result -> mWalletUtil.uploadCfgWithApi(state.getAccessToken(), _r->{}));
} else {
mWalletUtil.uploadCfgWithApi(state.getAccessToken(), _r->{});
}
} else {
Log.w(TAG, "not login");
mExecutor.submit(() -> mAppAuthSvr.doAuth(funID, _result -> mWalletUtil.uploadCfgWithApi(state.getAccessToken(), _r->{})));
}
}
});
// runOnUiThread(() -> {
// Intent intent = new Intent(this, BiometricActivity.class);
// intent.putExtra("action", "encrypt");
// intent.putExtra("funID", funId);
// intent.putExtra("account", account);
// intent.putExtra("password", password);
// startActivity(intent);
// });
}
public void authGetStoragePass(String funID, String account) {
Log.i(TAG, "authGetStoragePass with: " + account);
this.mFunID = funID;
mWalletUtil.updateParams(funID, account);
if (isGooglePlayServicesAvailable()) {
if (!mWalletUtil.localCfgExists(account)) {
if (!GoogleSignIn.hasPermissions(
GoogleSignIn.getLastSignedInAccount(getActivity()),
new Scope(DriveScopes.DRIVE_APPDATA))) {
loginAndRequestDrivePermission(RC_REQUEST_DRIVE_TO_READ);
} else {
mWalletUtil.downloadCfgWithGPS(_file -> mWalletUtil.getPassLocal());
}
} else {
mWalletUtil.getPassLocal();
}
} else {
if (!mWalletUtil.localCfgExists(account)) {
AuthState state = mAppAuthSvr.getCurrentState();
// 1. check whether the google account has been logged in, this situation occurs when non-google login
// 2. check if already had permission of drive appdata, add permission of drive appdata to auth_config
// 3. check if need refresh access token
if (state.isAuthorized()) {
if (state.getNeedsTokenRefresh()) {
Log.d(TAG, "need refresh accessToken");
mAppAuthSvr.refreshToken(funID, _result -> mWalletUtil.downloadCfgWithApi(state.getAccessToken(), _file -> mWalletUtil.getPassLocal()));
} else {
Log.d(TAG, "access token no need refresh");
mWalletUtil.downloadCfgWithApi(state.getAccessToken(), _file -> mWalletUtil.getPassLocal());
}
} else {
Log.w(TAG, "not login");
mExecutor.submit(() -> mAppAuthSvr.doAuth(funID, _result -> mWalletUtil.downloadCfgWithApi(state.getAccessToken(), _file -> mWalletUtil.getPassLocal())));
}
} else {
mWalletUtil.getPassLocal();
}
}
// runOnUiThread(() -> {
// Intent intent = new Intent(this, BiometricActivity.class);
// intent.putExtra("action", "decrypt");
// intent.putExtra("funID", funId);
// intent.putExtra("account", account);
// startActivity(intent);
// });
}
public void getClientId(String funID) {
Log.i(TAG, "getClientId ");
}
}

View File

@ -1,96 +0,0 @@
package com.cege.games.release.activity;
import static androidx.biometric.BiometricManager.Authenticators.BIOMETRIC_STRONG;
import static androidx.biometric.BiometricManager.Authenticators.DEVICE_CREDENTIAL;
import static androidx.biometric.BiometricPrompt.ERROR_USER_CANCELED;
import android.content.Intent;
import android.os.Bundle;
import android.security.keystore.KeyInfo;
import android.util.Base64;
import android.util.Log;
import androidx.appcompat.app.AppCompatActivity;
import androidx.biometric.BiometricManager;
import androidx.biometric.BiometricPrompt;
import com.cege.games.release.R;
import com.jc.jcfw.security.BiometricHelper;
import com.jc.jcfw.security.CryptographyManager;
import com.jc.jcfw.security.CryptographyManagerImpl;
import com.jc.jcfw.security.EncryptedData;
import javax.crypto.Cipher;
public class BiometricActivity extends AppCompatActivity {
private static final String TAG = BiometricActivity.class.getSimpleName();
private BiometricPrompt.PromptInfo promptInfo;
private CryptographyManager cryptographyManager;
@Override
public void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_biometric);
Log.i(TAG, "onCreate: " + getIntent().getDataString());
promptInfo = BiometricHelper.createPromptInfo(this);
cryptographyManager = new CryptographyManagerImpl();
Intent intent = getIntent();
String action = intent.getStringExtra("action");
String funId = intent.getStringExtra("funid");
String account = intent.getStringExtra("account");
// check if action is exists
if ("encrypt".equals(action)) {
String password = intent.getStringExtra("password");
authenticateToEncrypt(funId, password);
} else if ("decrypt".equals(action)) {
String iv = intent.getStringExtra("iv");
authenticateToDecrypt(account, iv);
}
}
public void authenticateToEncrypt(String funId, String text) {
if (BiometricManager.from(this)
.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) {
Cipher cipher = cryptographyManager.getInitializedCipherForEncryption("cebg_wallet_key");
BiometricPrompt biometricPrompt = BiometricHelper.createBiometricPrompt(this, _result -> {
if (_result.isError()) {
if (_result.getErrcode() == ERROR_USER_CANCELED) {
// close current activity
finish();
}
return;
}
EncryptedData encryptedData = cryptographyManager.encryptData(text, _result.getCipher());
String encryptedString = Base64.encodeToString(encryptedData.getCiphertext(), Base64.DEFAULT);
String ivString = Base64.encodeToString(encryptedData.getInitializationVector(), Base64.DEFAULT);
Log.i(TAG, "encrypted msg: " + encryptedString);
Log.i(TAG, "encrypted iv: " + ivString);
finish();
});
biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher));
}
}
public void authenticateToDecrypt(String text, String iv) {
if (BiometricManager.from(this)
.canAuthenticate(BIOMETRIC_STRONG | DEVICE_CREDENTIAL) == BiometricManager.BIOMETRIC_SUCCESS) {
byte[] ivData = Base64.decode(iv, Base64.DEFAULT);
byte[] textData = Base64.decode(text, Base64.DEFAULT);
Cipher cipher = cryptographyManager.getInitializedCipherForDecryption("cebg_wallet_key", ivData);
BiometricPrompt biometricPrompt = BiometricHelper.createBiometricPrompt(this, _result -> {
if (_result.isError()) {
if (_result.getErrcode() == ERROR_USER_CANCELED) {
// close current activity
finish();
}
return;
}
String decryptedMsg = cryptographyManager.decryptData(textData, _result.getCipher());
Log.i(TAG, "decrypted msg: " + decryptedMsg);
finish();
});
biometricPrompt.authenticate(promptInfo, new BiometricPrompt.CryptoObject(cipher));
}
}
}

View File

@ -1,244 +0,0 @@
package com.cege.games.release.activity;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Intent;
import android.graphics.Bitmap;
import android.util.Log;
import android.webkit.ConsoleMessage;
import android.webkit.CookieManager;
import android.webkit.WebChromeClient;
import android.webkit.WebResourceError;
import android.webkit.WebResourceRequest;
import android.webkit.WebResourceResponse;
import android.webkit.WebSettings;
import android.webkit.WebView;
import android.webkit.WebViewClient;
import androidx.annotation.NonNull;
import com.cege.games.release.MainApplication;
import com.cege.games.release.R;
import com.cege.games.release.ui.UIManager;
import com.cege.games.release.webpage.events.CallJSEvent;
import com.cege.games.release.webpage.events.ProxyCBEvent;
import com.cege.games.release.webpage.events.WebPageEvent;
import com.cege.games.release.webpage.WalletInterface;
import com.google.common.collect.Maps;
import com.jc.jcfw.JcSDK;
import com.jc.jcfw.util.UIUtils;
import org.greenrobot.eventbus.EventBus;
import org.greenrobot.eventbus.Subscribe;
import org.greenrobot.eventbus.ThreadMode;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;
import java.util.Map;
import java.util.function.Consumer;
public class WebPageActivity extends Activity {
private WebView mWebView;
private final String FUNID_PREFIX = "webpage_";
private final Map<String, Consumer<JSONObject>> actionMap = Maps.newHashMap();
private static final String TAG = WebPageActivity.class.getSimpleName();
@SuppressLint({ "SetJavaScriptEnabled", "DefaultLocale" })
@Override
protected void onCreate(android.os.Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
resistActions();
setContentView(R.layout.activity_web_page);
WebView.setWebContentsDebuggingEnabled(true);
mWebView = findViewById(R.id.web_view);
WebSettings webSettings = mWebView.getSettings();
webSettings.setJavaScriptEnabled(true);
webSettings.setDomStorageEnabled(true);
webSettings.setDatabaseEnabled(true);
webSettings.setAllowContentAccess(true);
webSettings.setAppCacheEnabled(true);
webSettings.setBuiltInZoomControls(true);
webSettings.setUseWideViewPort(true);
webSettings.setLoadWithOverviewMode(true);
webSettings.setMixedContentMode(WebSettings.MIXED_CONTENT_ALWAYS_ALLOW);
// custom user agent
webSettings.setUserAgentString(webSettings.getUserAgentString() + " android_game_web");
CookieManager.getInstance().setAcceptThirdPartyCookies(mWebView, true);
// get url from intent
Intent intent = getIntent();
String url = intent.getStringExtra("url");
// show web view
mWebView.loadUrl(url);
mWebView.addJavascriptInterface(new WalletInterface(this), "cfwallet_JuEd8Ql5over8kneww");
mWebView.setWebChromeClient(new WebChromeClient() {
@Override
public void onReceivedTitle(WebView view, String title) {
super.onReceivedTitle(view, title);
Log.i(TAG, "onReceivedTitle: " + title);
}
@Override
public boolean onConsoleMessage(ConsoleMessage consoleMessage) {
Log.e(TAG, consoleMessage.message());
return true;
}
});
mWebView.setWebViewClient(new WebViewClient() {
@Override
public boolean shouldOverrideUrlLoading(WebView view, WebResourceRequest request) {
return super.shouldOverrideUrlLoading(view, request);
// if ("www.example.com".equals(request.getUrl().getHost())) {
// // This is my website, so do not override; let my WebView load the page
// return false;
// }
}
@Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
super.onPageStarted(view, url, favicon);
Log.i(TAG, "onPageStarted: " + url);
String gameData = MainApplication.application.getGameData();
String jsCode = String.format("window.platform='android_game_web'; window.gameData='%s';", gameData);
callPageJS(jsCode);
}
@Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(view, url);
}
@Override
public void onLoadResource(WebView view, String url) {
Log.i(TAG, "onLoadResource: " + url);
}
@Override
public void onReceivedError(WebView view, WebResourceRequest request, WebResourceError error) {
super.onReceivedError(view, request, error);
Log.e(TAG, "onReceivedError: " + error);
}
@Override
public void onReceivedHttpError(WebView view, WebResourceRequest request, WebResourceResponse errorResponse) {
super.onReceivedHttpError(view, request, errorResponse);
Log.e(TAG, "onReceivedHttpError: " + errorResponse);
}
@Override
public void onReceivedSslError(WebView view, android.webkit.SslErrorHandler handler,
android.net.http.SslError error) {
Log.e(TAG, "onReceivedSslError: " + error.toString());
}
});
EventBus.getDefault().register(this);
}
@Override
public void onStart() {
super.onStart();
UIManager.getSingleton().onStartActivity(this);
}
@Override
public void onDestroy() {
EventBus.getDefault().unregister(this);
super.onDestroy();
}
private void asyncThread(Runnable runnable) {
new Thread(runnable).start();
}
private void resistActions() {
actionMap.put("closepage", _data -> {
finish();
});
actionMap.put("proxyMethod", _data -> {
try {
String funId = FUNID_PREFIX + _data.getString("funid");
String methodName = _data.getString("methodname");
JSONArray params = _data.getJSONArray("params");
String[] paramArr = new String[params.length()];
for (int i = 0; i < params.length(); i++) {
paramArr[i] = params.getString(i);
}
JcSDK.callNativeJS(funId, methodName, paramArr);
} catch (JSONException e) {
throw new RuntimeException(e);
}
});
actionMap.put("scanQRCode", _data -> {
try {
String funId = FUNID_PREFIX + _data.getString("funid");
String title = _data.getString("title");
UIManager.getSingleton().showQRScan(funId, title);
} catch (JSONException e) {
throw new RuntimeException(e);
}
});
actionMap.put("showQRCode", _data -> {
try {
String funId = FUNID_PREFIX + _data.getString("funid");
String title = _data.getString("title");
UIUtils.showQRCode(this, title, "");
} catch (JSONException e) {
throw new RuntimeException(e);
}
});
}
@Override
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
UIManager.getSingleton().onActivityResult(this, requestCode, resultCode, data);
}
@Override
public void onRequestPermissionsResult(int requestCode, @NonNull String[] permissions, @NonNull int[] grantResults) {
super.onRequestPermissionsResult(requestCode, permissions, grantResults);
// Forward results to EasyPermissions
UIManager.getSingleton().onRequestPermissionsResult(requestCode, permissions, grantResults);
}
public void callPageJS(String javascript) {
mWebView.evaluateJavascript(javascript, s -> {
Log.i("PAGE", s);
});
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onPageEvent(WebPageEvent event) {
Log.i(TAG, "on page event: " + event.getDataStr());
try {
JSONObject data = new JSONObject(event.getDataStr());
String action = data.getString("action");
// JSONArray params = data.getJSONArray("params");
if (actionMap.containsKey(action)) {
actionMap.get(action).accept(data);
} else {
Log.w(TAG, String.format("unknown action: %s, data: %s", action, event.getDataStr()));
}
} catch (JSONException e) {
throw new RuntimeException(e);
}
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onCallJSEvent(CallJSEvent event) {
String funId = event.getFunId();
if (funId.indexOf(FUNID_PREFIX) == 0) {
funId = funId.replace(FUNID_PREFIX, "");
}
callPageJS("nativeCall('" + funId + "', '" + event.getData() + "');");
}
@Subscribe(threadMode = ThreadMode.MAIN)
public void onProxyCBEvent(ProxyCBEvent event) {
String funId = event.getFunId();
if (funId.indexOf(FUNID_PREFIX) == 0) {
funId = funId.replace(FUNID_PREFIX, "");
}
callPageJS("proxyCallback('" + funId + "', '" + event.getData() + "');");
}
}

View File

@ -1,393 +0,0 @@
package com.cege.games.release.appauth;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.text.TextUtils;
import android.util.Log;
import androidx.annotation.MainThread;
import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.annotation.WorkerThread;
import androidx.browser.customtabs.CustomTabsIntent;
import com.jc.jcfw.JcSDK;
import com.jc.jcfw.appauth.AuthStateManager;
import com.jc.jcfw.appauth.JConfiguration;
import com.jc.jcfw.util.ThreadUtils;
import net.openid.appauth.AppAuthConfiguration;
import net.openid.appauth.AuthState;
import net.openid.appauth.AuthorizationException;
import net.openid.appauth.AuthorizationRequest;
import net.openid.appauth.AuthorizationResponse;
import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration;
import net.openid.appauth.ClientAuthentication;
import net.openid.appauth.ClientSecretBasic;
import net.openid.appauth.RegistrationRequest;
import net.openid.appauth.RegistrationResponse;
import net.openid.appauth.ResponseTypeValues;
import net.openid.appauth.TokenRequest;
import net.openid.appauth.TokenResponse;
import net.openid.appauth.browser.AnyBrowserMatcher;
import net.openid.appauth.browser.BrowserMatcher;
import java.util.Collections;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.atomic.AtomicReference;
import java.util.function.Consumer;
public class AppAuthSvr {
private final String TAG = getClass().getSimpleName();
private final Activity activity;
private AuthorizationService mAuthService;
private AuthStateManager mAuthStateManager;
private JConfiguration mConfiguration;
private ExecutorService mExecutor;
private final AtomicReference<String> mClientId = new AtomicReference<>();
private final AtomicReference<AuthorizationRequest> mAuthRequest = new AtomicReference<>();
private final AtomicReference<CustomTabsIntent> mAuthIntent = new AtomicReference<>();
private CountDownLatch mAuthIntentLatch = new CountDownLatch(1);
private String mFunID;
private static final int RC_AUTH = 0X04;
private Consumer<String> loginCbAction = null;
@NonNull
private final BrowserMatcher mBrowserMatcher = AnyBrowserMatcher.INSTANCE;
public AppAuthSvr(Activity activity) {
this.activity = activity;
}
public void init(ExecutorService executorService) {
mExecutor = executorService;
mAuthStateManager = AuthStateManager.getInstance(activity);
mConfiguration = JConfiguration.getInstance(activity);
mExecutor.submit(this::initializeAppAuth);
}
public void setFunID(String funID) {
this.mFunID = funID;
}
public void setLoginCbAction(Consumer<String> func) {
this.loginCbAction = func;
}
public AuthState getCurrentState() {
return mAuthStateManager.getCurrent();
}
/**
* Performs the authorization request, using the browser selected in the
* spinner,
* and a user-provided `login_hint` if available.
*/
@WorkerThread
public void doAuth(String funID, Consumer<String> func) {
this.mFunID = funID;
this.loginCbAction = func;
try {
mAuthIntentLatch.await();
} catch (InterruptedException ex) {
Log.w(TAG, "Interrupted while waiting for auth intent");
}
Intent intent = mAuthService.getAuthorizationRequestIntent(
mAuthRequest.get(),
mAuthIntent.get());
activity.startActivityForResult(intent, RC_AUTH);
}
public void parseLoginResult(@NonNull Intent data) {
AuthorizationResponse response = AuthorizationResponse.fromIntent(data);
AuthorizationException ex = AuthorizationException.fromIntent(data);
if (response != null || ex != null) {
mAuthStateManager.updateAfterAuthorization(response, ex);
}
if (response != null && response.authorizationCode != null) {
// authorization code exchange is required
mAuthStateManager.updateAfterAuthorization(response, ex);
exchangeAuthorizationCode(response);
} else if (ex != null) {
Log.i(TAG, "Authorization flow failed: " + ex.getMessage());
errorCB("Authorization flow failed: " + ex.getMessage());
} else {
Log.i(TAG, "No authorization state retained - reauthorization required");
errorCB("No authorization state retained - reauthorization required");
}
}
public void refreshToken(String funID, Consumer<String> func) {
this.mFunID = funID;
this.loginCbAction = func;
AuthState state = getCurrentState();
performTokenRequest(state.createTokenRefreshRequest(), this::handleCodeExchangeResponse);
}
/**
* Initializes the authorization service configuration if necessary, either from
* the local
* static values or by retrieving an OpenID discovery document.
*/
@WorkerThread
private void initializeAppAuth() {
Log.i(TAG, "Initializing AppAuth");
recreateAuthorizationService();
if (mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration() != null) {
// configuration is already created, skip to client initialization
Log.i(TAG, "auth config already established");
initializeClient();
return;
}
// if we are not using discovery, build the authorization service configuration
// directly
// from the static configuration values.
if (mConfiguration.getDiscoveryUri() == null) {
Log.i(TAG, "Creating auth config from res/raw/auth_config.json");
AuthorizationServiceConfiguration config = new AuthorizationServiceConfiguration(
mConfiguration.getAuthEndpointUri(),
mConfiguration.getTokenEndpointUri(),
mConfiguration.getRegistrationEndpointUri(),
mConfiguration.getEndSessionEndpoint());
mAuthStateManager.replace(new AuthState(config));
initializeClient();
return;
}
// WrongThread inference is incorrect for lambdas
// noinspection WrongThread
Log.i(TAG, "Retrieving OpenID discovery doc");
AuthorizationServiceConfiguration.fetchFromUrl(
mConfiguration.getDiscoveryUri(),
this::handleConfigurationRetrievalResult,
mConfiguration.getConnectionBuilder());
}
@MainThread
private void handleConfigurationRetrievalResult(
AuthorizationServiceConfiguration config,
AuthorizationException ex) {
if (config == null) {
Log.i(TAG, "Failed to retrieve discovery document", ex);
return;
}
Log.i(TAG, "Discovery document retrieved");
mAuthStateManager.replace(new AuthState(config));
mExecutor.submit(this::initializeClient);
}
private void recreateAuthorizationService() {
if (mAuthService != null) {
Log.i(TAG, "Discarding existing AuthService instance");
mAuthService.dispose();
}
mAuthService = createAuthorizationService();
mAuthRequest.set(null);
mAuthIntent.set(null);
}
private AuthorizationService createAuthorizationService() {
Log.i(TAG, "Creating authorization service");
AppAuthConfiguration.Builder builder = new AppAuthConfiguration.Builder();
builder.setBrowserMatcher(mBrowserMatcher);
builder.setConnectionBuilder(mConfiguration.getConnectionBuilder());
return new AuthorizationService(activity, builder.build());
}
private void createAuthRequest(@Nullable String loginHint) {
Log.i(TAG, "Creating auth request for login hint: " + loginHint);
AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder(
mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
mClientId.get(),
ResponseTypeValues.CODE,
mConfiguration.getRedirectUri())
// apple need `form_post` when authorization_scope has `name email `
// .setResponseMode("form_post")
// .setResponseType("code id_token")
.setScope(mConfiguration.getScope());
if (!TextUtils.isEmpty(loginHint)) {
authRequestBuilder.setLoginHint(loginHint);
}
mAuthRequest.set(authRequestBuilder.build());
}
private void warmUpBrowser() {
mAuthIntentLatch = new CountDownLatch(1);
mExecutor.execute(() -> {
Log.i(TAG, "Warming up browser instance for auth request");
Uri uri = mAuthRequest.get().toUri();
Log.d(TAG, "URI: " + uri);
CustomTabsIntent.Builder intentBuilder = mAuthService.createCustomTabsIntentBuilder(uri);
mAuthIntent.set(intentBuilder.build());
mAuthIntentLatch.countDown();
});
}
@MainThread
private void initializeAuthRequest() {
createAuthRequest("");
warmUpBrowser();
displayAuthOptions();
}
/**
* Initiates a dynamic registration request if a client ID is not provided by
* the static
* configuration.
*/
@WorkerThread
private void initializeClient() {
if (mConfiguration.getClientId() != null) {
Log.i(TAG, "Using static client ID: " + mConfiguration.getClientId());
// use a statically configured client ID
mClientId.set(mConfiguration.getClientId());
ThreadUtils.runInMain(this::initializeAuthRequest);
return;
}
RegistrationResponse lastResponse = mAuthStateManager.getCurrent().getLastRegistrationResponse();
if (lastResponse != null) {
Log.i(TAG, "Using dynamic client ID: " + lastResponse.clientId);
// already dynamically registered a client ID
mClientId.set(lastResponse.clientId);
ThreadUtils.runInMain(this::initializeAuthRequest);
return;
}
// WrongThread inference is incorrect for lambdas
// noinspection WrongThread
Log.i(TAG, "Dynamically registering client");
RegistrationRequest registrationRequest = new RegistrationRequest.Builder(
mAuthStateManager.getCurrent().getAuthorizationServiceConfiguration(),
Collections.singletonList(mConfiguration.getRedirectUri()))
.setTokenEndpointAuthenticationMethod(ClientSecretBasic.NAME)
.build();
mAuthService.performRegistrationRequest(
registrationRequest,
this::handleRegistrationResponse);
}
private void handleRegistrationResponse(
RegistrationResponse response,
AuthorizationException ex) {
mAuthStateManager.updateAfterRegistration(response, ex);
if (response == null) {
Log.i(TAG, "Failed to dynamically register client", ex);
return;
}
Log.i(TAG, "Dynamically registered client: " + response.clientId);
mClientId.set(response.clientId);
initializeAuthRequest();
}
private void displayAuthOptions() {
AuthState state = mAuthStateManager.getCurrent();
AuthorizationServiceConfiguration config = state.getAuthorizationServiceConfiguration();
String authEndpointStr;
if (config.discoveryDoc != null) {
authEndpointStr = "Discovered auth endpoint: \n";
} else {
authEndpointStr = "Static auth endpoint: \n";
}
authEndpointStr += config.authorizationEndpoint;
Log.i(TAG, authEndpointStr);
String clientIdStr;
if (state.getLastRegistrationResponse() != null) {
clientIdStr = "Dynamic client ID: \n";
} else {
clientIdStr = "Static client ID: \n";
}
clientIdStr += mClientId;
Log.i(TAG, clientIdStr);
}
@MainThread
private void exchangeAuthorizationCode(AuthorizationResponse authorizationResponse) {
Log.d(TAG, "Exchanging authorization code");
performTokenRequest(
authorizationResponse.createTokenExchangeRequest(),
this::handleCodeExchangeResponse);
}
@MainThread
private void performTokenRequest(
TokenRequest request,
AuthorizationService.TokenResponseCallback callback) {
ClientAuthentication clientAuthentication;
try {
clientAuthentication = mAuthStateManager.getCurrent().getClientAuthentication();
} catch (ClientAuthentication.UnsupportedAuthenticationMethod ex) {
Log.d(TAG, "Token request cannot be made, client authentication for the token "
+ "endpoint could not be constructed (%s)", ex);
return;
}
mAuthService.performTokenRequest(
request,
clientAuthentication,
callback);
}
@WorkerThread
private void handleCodeExchangeResponse(
@Nullable TokenResponse tokenResponse,
@Nullable AuthorizationException authException) {
mAuthStateManager.updateAfterTokenResponse(tokenResponse, authException);
if (!mAuthStateManager.getCurrent().isAuthorized()) {
final String message = "Authorization Code exchange failed: "
+ ((authException != null) ? authException.error : "");
Log.d(TAG, message);
errorCB(message);
} else {
checkAuthStateAndCB();
}
}
private void checkAuthStateAndCB() {
AuthState state = mAuthStateManager.getCurrent();
Log.d(TAG, "login success, auth state: " + state.isAuthorized());
Log.d(TAG, "id token : " + state.getIdToken());
Log.d(TAG, "access token: " + state.getAccessToken());
Log.d(TAG, "refresh token: " + state.getRefreshToken());
mAuthStateManager.replace(state);
if (loginCbAction != null) {
mExecutor.submit(() -> {
loginCbAction.accept("success");
clearParams();
});
} else {
successCB(state.getIdToken());
}
}
private void clearParams() {
this.mFunID = null;
this.loginCbAction = null;
}
public void errorCB(String msg) {
JcSDK.nativeCb(mFunID, msg, null);
clearParams();
}
public void successCB(String dataStr) {
JcSDK.nativeCb(mFunID, null, dataStr);
clearParams();
}
}

View File

@ -1,52 +0,0 @@
package com.cege.games.release.oauth;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import android.os.Bundle;
import android.util.Log;
import androidx.annotation.Nullable;
import com.cege.games.release.MainActivity;
import com.jc.jcfw.JcSDK;
public class OAuthLoginCbActivity extends Activity {
private static final String TAG = OAuthLoginCbActivity.class.getSimpleName();
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
Log.d(TAG, "receive oauth login callback");
Intent intent = getIntent();
if (Intent.ACTION_VIEW.equals(intent.getAction())) {
Uri uri = intent.getData();
String error = uri.getQueryParameter("error");
String state = uri.getQueryParameter("state");
if (null != error && !error.isEmpty()) {
JcSDK.nativeCb(state, error, null);
} else {
String token = uri.getQueryParameter("token");
// if token is null, get token and state from uri fragment
if (null == token || "undefined".equals(token) || token.isEmpty()){
String fragment = uri.getFragment();
String[] vals = fragment.split("&");
for (String val : vals) {
if (val.startsWith("token=")) {
token = val.substring(6);
} else if (val.startsWith("id_token=")) {
token = val.substring(9);
} else if (val.startsWith("state=")) {
state = val.substring(6);
}
}
}
JcSDK.nativeCb(state, null, token);
}
Intent intentMain = new Intent(this, MainActivity.class);
startActivity(intentMain);
finish();
}
}
}

View File

@ -1,61 +0,0 @@
package com.cege.games.release.oauth;
import android.app.Activity;
import android.content.Intent;
import android.net.Uri;
import net.openid.appauth.AuthorizationRequest;
import net.openid.appauth.AuthorizationService;
import net.openid.appauth.AuthorizationServiceConfiguration;
import org.json.JSONException;
import org.json.JSONObject;
public class OAuthUtil {
private final Activity mActivity;
public OAuthUtil(Activity activity) {
this.mActivity = activity;
}
/**
*
* @param funId
* @param jsonData: {
* "endpoint": "",
* "client_id": "",
* "redirect_uri": "",
* "response_type": "code",
* "response_mode": "form_post", nullable
* "scopes": "",
* }
* @throws JSONException
*/
public void startLogin(String funId, String jsonData) throws JSONException {
JSONObject data = new JSONObject(jsonData);
AuthorizationServiceConfiguration config = new AuthorizationServiceConfiguration(
Uri.parse(data.getString("endpoint")),
Uri.parse("")
);
AuthorizationRequest.Builder authRequestBuilder = new AuthorizationRequest.Builder(
config,
data.getString("client_id"),
data.getString("response_type"),
Uri.parse(data.getString("redirect_uri"))
);
String[] scopes = data.getString("scopes").split(" +");
if (data.has("response_mode")) {
authRequestBuilder.setResponseMode(data.getString("response_mode"));
}
AuthorizationRequest authRequest = authRequestBuilder
.setScopes(scopes)
.setCodeVerifier(null, null, null)
.setState(funId)
.setNonce(funId)
.build();
AuthorizationService service = new AuthorizationService(this.mActivity);
Intent authIntent = service.getAuthorizationRequestIntent(authRequest);
this.mActivity.startActivity(authIntent);
}
}

View File

@ -1,62 +0,0 @@
package com.cege.games.release.tiktokapi;
import android.app.Activity;
import android.content.Intent;
import android.os.Bundle;
import android.util.Log;
import com.bytedance.sdk.open.tiktok.CommonConstants;
import com.bytedance.sdk.open.tiktok.TikTokOpenApiFactory;
import com.bytedance.sdk.open.tiktok.api.TikTokOpenApi;
import com.bytedance.sdk.open.tiktok.authorize.model.Authorization;
import com.bytedance.sdk.open.tiktok.common.handler.IApiEventHandler;
import com.bytedance.sdk.open.tiktok.common.model.BaseReq;
import com.bytedance.sdk.open.tiktok.common.model.BaseResp;
import com.bytedance.sdk.open.tiktok.share.Share;
import com.jc.jcfw.JcSDK;
import androidx.annotation.Nullable;
public class TikTokEntryActivity extends Activity implements IApiEventHandler {
private static final String TAG = TikTokEntryActivity.class.getSimpleName();
TikTokOpenApi ttOpenApi;
@Override
public void onCreate(@Nullable Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
ttOpenApi= TikTokOpenApiFactory.create(this);
ttOpenApi.handleIntent(getIntent(),this); // receive and parse callback
}
@Override
public void onReq(BaseReq req) {
}
@Override
public void onResp(BaseResp resp) {
if (resp instanceof Authorization.Response) {
Authorization.Response response = (Authorization.Response) resp;
// Log.i(TAG, "errorCode: " + response.errorCode);
// Log.i(TAG, "errorMsg: " + response.errorMsg);
// Log.i(TAG, "authCode: " + response.authCode);
// Log.i(TAG, "state: " + response.state);
// Log.i(TAG, "grantedPermissions: " + response.grantedPermissions);
if (response.errorCode == 0) {
JcSDK.nativeCb(response.state, null, response.authCode);
} else {
JcSDK.nativeCb(response.state, response.errorMsg, null);
}
finish();
} else if (resp.getType() == CommonConstants.ModeType.SHARE_CONTENT_TO_TT_RESP) {
Share.Response response = (Share.Response) resp;
Log.i(TAG, "share result code" + response.errorCode + " errorMessage" + response.errorMsg);
if (response.errorCode == 0) {
JcSDK.nativeCb(response.state, null, "1");
} else {
JcSDK.nativeCb(response.state, response.errorMsg, null);
}
finish();
}
}
@Override
public void onErrorIntent(@Nullable Intent intent) {
JcSDK.nativeCb(null, "error intent", null);
}
}

View File

@ -1,222 +0,0 @@
package com.cege.games.release.wallet;
import android.content.Context;
import android.util.Log;
import com.cege.games.release.R;
import com.google.android.gms.auth.api.signin.GoogleSignIn;
import com.google.android.gms.auth.api.signin.GoogleSignInAccount;
import com.google.api.client.googleapis.extensions.android.gms.auth.GoogleAccountCredential;
import com.google.api.client.googleapis.json.GoogleJsonResponseException;
import com.google.api.services.drive.Drive;
import com.google.api.services.drive.DriveScopes;
import com.google.common.base.Strings;
import com.jc.jcfw.JcSDK;
import com.jc.jcfw.NativeResult;
import com.jc.jcfw.util.DriveUtils;
import com.jc.jcfw.util.DriverApiUtils;
import com.jc.jcfw.util.FileUtils;
import org.json.JSONException;
import org.json.JSONObject;
import java.io.File;
import java.io.IOException;
import java.util.Collections;
import java.util.function.Consumer;
public class WalletUtil {
private final Context mContext;
private String funID;
private String account;
public WalletUtil(Context context) {
this.mContext = context;
}
private final String TAG = getClass().getSimpleName();
public void updateParams(String funID, String account) {
this.funID = funID;
this.account = account;
}
public void clearParams() {
this.funID = null;
this.account = null;
}
public String getAccount() {
return account;
}
public void errorCB(String msg) {
JcSDK.nativeCb(funID, msg, null);
clearParams();
}
public void successCB(String dataStr) {
JcSDK.nativeCb(funID, null, dataStr);
clearParams();
}
public static String generateFileName(String account) {
return String.format("wallet_%s.json", account);
}
public File getWalletCfgFile(String account) {
String filename = generateFileName(account);
File dic = new File(mContext.getFilesDir() + "/wallets");
if (!dic.exists()) {
dic.mkdir();
}
return new File(mContext.getFilesDir() + "/wallets", filename);
}
public void savePassToLocal(String pass, Consumer<File> func) {
File filePath = getWalletCfgFile(account);
JSONObject content = new JSONObject();
try {
content.put("pass", pass);
FileUtils.writeFile(filePath, content.toString());
func.accept(filePath);
} catch (JSONException | IOException e) {
errorCB(e.getMessage());
}
}
public void getPassLocal() {
try {
JSONObject json = loadLocalCfg(account);
String passEncrypted = json.getString("pass");
String passDecrypted = JcSDK.decryptPass(account, passEncrypted);
successCB(passDecrypted);
} catch (JSONException | IOException e) {
errorCB(e.getMessage());
}
}
public boolean localCfgExists(String account) {
File filePath = getWalletCfgFile(account);
return filePath.exists();
}
public JSONObject loadLocalCfg(String account) throws JSONException, IOException {
File filePath = getWalletCfgFile(account);
if (!filePath.exists()) {
return null;
}
return FileUtils.readJsonFromFile(filePath);
}
public void uploadCfgWithGPS(Consumer<NativeResult> func) {
GoogleSignInAccount ga = GoogleSignIn.getLastSignedInAccount(mContext);
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(mContext,
Collections.singletonList(DriveScopes.DRIVE_APPDATA));
credential.setSelectedAccount(ga.getAccount());
Drive service = DriveUtils.generateService(credential, mContext.getString(R.string.app_name));
try {
File file = getWalletCfgFile(account);
String fileName = file.getName();
String fileId = DriveUtils.queryOneAppFile(service, fileName);
if (Strings.isNullOrEmpty(fileId)) {
Log.i(TAG, String.format("%s not exists in drive, upload...", fileName));
fileId = DriveUtils.uploadAppFile(service, file, "application/json");
}
Log.i(TAG, "File ID: " + fileId);
func.accept(new NativeResult(funID, null, fileId));
successCB(fileId);
} catch (GoogleJsonResponseException e) {
Log.i(TAG, "Unable to create file: " + e.getDetails());
func.accept(new NativeResult(funID, e.getMessage(), null));
errorCB("Unable to create file: " +e.getMessage());
} catch (IOException e) {
Log.i(TAG, e.getMessage());
func.accept(new NativeResult(funID, e.getMessage(), null));
errorCB("Unable to create file: " + e.getMessage());
}
}
public void downloadCfgWithGPS(Consumer<File> func) {
GoogleSignInAccount ga = GoogleSignIn.getLastSignedInAccount(mContext);
GoogleAccountCredential credential = GoogleAccountCredential.usingOAuth2(mContext,
Collections.singletonList(DriveScopes.DRIVE_APPDATA));
credential.setSelectedAccount(ga.getAccount());
Drive service = DriveUtils.generateService(credential, mContext.getString(R.string.app_name));
String fileName = generateFileName(account);
String fileId = DriveUtils.queryOneAppFile(service, fileName);
if (Strings.isNullOrEmpty(fileId)) {
Log.i(TAG, "file not found in drive");
errorCB("file not found in drive");
return;
}
boolean downloadSuccess = false;
int count = 0;
File fileLocal = getWalletCfgFile(account);
while (!downloadSuccess && count++ < 10) {
Log.i(TAG, String.format("download file: %s with GPS, try: %d", fileName, count));
try {
String jsonStr = DriveUtils.downloadFile(service, fileId);
FileUtils.writeFile(fileLocal, jsonStr);
downloadSuccess = true;
} catch (IOException e) {
Log.i(TAG, "error download file with GPS");
}
}
if (downloadSuccess) {
func.accept(fileLocal);
} else {
errorCB("error download file with GPS");
}
}
public void downloadCfgWithApi(String accessToken, Consumer<File> func) {
DriverApiUtils api = new DriverApiUtils(accessToken);
String fileName = generateFileName(account);
File fileLocal = getWalletCfgFile(account);
boolean downloadSuccess = false;
int count = 0;
while (!downloadSuccess && count++ < 10) {
Log.i(TAG, String.format("download file: %s with api, try: %d", fileName, count));
try {
String fileId = api.queryOneAppFile(fileName);
if (Strings.isNullOrEmpty(fileId)) {
Log.i(TAG, "file not found in drive");
throw new IOException();
}
String jsonStr = api.fileInfo(fileId);
FileUtils.writeFile(fileLocal, jsonStr);
downloadSuccess = true;
} catch (IOException | JSONException e) {
Log.i(TAG, "error download file with api");
}
}
if (downloadSuccess) {
func.accept(fileLocal);
} else {
errorCB("error download file with api");
}
}
public void uploadCfgWithApi(String accessToken, Consumer<NativeResult> func) {
DriverApiUtils api = new DriverApiUtils(accessToken);
File fileLocal = getWalletCfgFile(account);
try {
String fileName = generateFileName(account);
String fileId = api.queryOneAppFile(fileName);
if (Strings.isNullOrEmpty(fileId)) {
String rep = api.uploadFile(fileLocal, "application/json");
JSONObject repData = new JSONObject(rep);
fileId = repData.getString("id");
}
Log.i(TAG, "success upload file with api, ID: " + fileId);
func.accept(new NativeResult(funID, null, fileId));
successCB(fileId);
} catch (IOException | JSONException e) {
func.accept(new NativeResult(funID, e.getMessage(), null));
errorCB("error upload file with api: " + e.getMessage());
}
}
}

View File

@ -1,7 +1,5 @@
package com.jc.jcfw;
import static com.cege.games.release.Constants.FUNID_PREFIX;
import android.annotation.SuppressLint;
import android.content.ActivityNotFoundException;
import android.content.Intent;
@ -9,17 +7,13 @@ import android.net.Uri;
import android.util.Log;
import com.cege.games.release.MainActivity;
import com.cege.games.release.MainApplication;
import com.cege.games.release.ui.UIManager;
import com.cege.games.release.webpage.events.CallJSEvent;
import com.cege.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 com.unity3d.player.UnityPlayer;
import org.cocos2dx.lib.CocosJSHelper;
import org.greenrobot.eventbus.EventBus;
import org.json.JSONException;
import org.json.JSONObject;
@ -36,27 +30,11 @@ public class JcSDK {
@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#
@ -100,47 +78,12 @@ public class JcSDK {
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 signWithOAuth(String funid, String jsonData) {
MainActivity.app.oauthLogin(funid, jsonData);
}
public static void signOutGoogle(String funid) {
MainActivity.app.signOutGoogle(funid);
}
public static void logEvent(String content) {
MainActivity.app.logEvent(content);
}
@ -176,63 +119,16 @@ public class JcSDK {
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));
toUnity(funId, error, dataStr);
}
public static void nativeCb(NativeResult result) {
nativeCb(result.getFunid(), result.getError(), result.getDataStr());
toUnity(result.getFunid(), result.getError(), result.getDataStr());
}
public static void toUnity(String funId, String error, String dataStr) {

View File

@ -1,8 +1,6 @@
apply from: "config.gradle"
include ':app'
rootProject.name = "HeadlessCocos"
include ':libcocos2dx'
project(':libcocos2dx').projectDir = new File(ext.cfgs.cocos2dxBasePath + '/cocos/platform/android/libcocos2dx')
include ':UnityDataAssetPack'
project(':UnityDataAssetPack').projectDir = new File(ext.cfgs.unityAndroidProject + '/UnityDataAssetPack')