update buildteamplate
This commit is contained in:
parent
a68805ba04
commit
14785fa079
@ -1,60 +1,66 @@
|
||||
/****************************************************************************
|
||||
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
Copyright (c) 2015-2016 Chukong Technologies Inc.
|
||||
Copyright (c) 2017-2018 Xiamen Yaji Software Co., Ltd.
|
||||
|
||||
http://www.cocos2d-x.org
|
||||
http://www.cocos2d-x.org
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
****************************************************************************/
|
||||
package org.cocos2dx.javascript;
|
||||
|
||||
import org.cocos2dx.lib.Cocos2dxActivity;
|
||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
|
||||
import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.walletconnect.Session;
|
||||
|
||||
import android.content.ActivityNotFoundException;
|
||||
import android.content.pm.PackageInfo;
|
||||
import android.content.pm.PackageManager;
|
||||
import android.net.Uri;
|
||||
import android.os.Bundle;
|
||||
|
||||
import android.content.Intent;
|
||||
import android.content.res.Configuration;
|
||||
import android.os.Looper;
|
||||
import android.net.Uri;
|
||||
import android.os.Build;
|
||||
import android.os.Bundle;
|
||||
import android.util.Log;
|
||||
import android.widget.Toast;
|
||||
|
||||
import androidx.annotation.RequiresApi;
|
||||
|
||||
import com.youme.voiceengine.MemberChange;
|
||||
import com.youme.voiceengine.YouMeCallBackInterface;
|
||||
import com.youme.voiceengine.YouMeConst;
|
||||
import com.youme.voiceengine.api;
|
||||
import com.youme.voiceengine.mgr.YouMeManager;
|
||||
|
||||
import java.util.Arrays;
|
||||
import org.cocos2dx.javascript.wc.JWCSession;
|
||||
import org.cocos2dx.lib.Cocos2dxActivity;
|
||||
import org.cocos2dx.lib.Cocos2dxGLSurfaceView;
|
||||
import org.cocos2dx.lib.Cocos2dxJavascriptJavaBridge;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.walletconnect.Session;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Objects;
|
||||
|
||||
import kotlin.Unit;
|
||||
import kotlin.jvm.functions.Function1;
|
||||
|
||||
public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterface , Session.Callback {
|
||||
private static AppActivity appActivity = null;
|
||||
private static final String TAG = "AppActivity";
|
||||
private static final String appKey="YOUME1838B3633FF1410BDC9124BBD806F245B9D2E5AC";
|
||||
private static final String appSecret="q6B570yTyj/00Nk4mYZtgDwyew5v05t13V1vo4mxpEuAaWUiinAyVxG41sNu3vsFe8sipOLfKfIVYGhzpQrqzvj5sId3mrBfj/s65a2gp36yDrI/nX5BnUAJB317SEosR6xLoPuhBvHU+/1DWI7nKSKaRNxnQiC46PJKFc2kX50BAAE=";
|
||||
|
||||
|
||||
@Override
|
||||
protected void onCreate(Bundle savedInstanceState) {
|
||||
YouMeManager.Init(this);
|
||||
@ -70,175 +76,173 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
||||
}
|
||||
api.SetCallback(this);
|
||||
api.init(appKey,appSecret,0,"");
|
||||
|
||||
|
||||
// DO OTHER INITIALIZATION BELOW
|
||||
SDKWrapper.getInstance().init(this);
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public Cocos2dxGLSurfaceView onCreateView() {
|
||||
Cocos2dxGLSurfaceView glSurfaceView = new Cocos2dxGLSurfaceView(this);
|
||||
// TestCpp should create stencil buffer
|
||||
glSurfaceView.setEGLConfigChooser(5, 6, 5, 0, 16, 8);
|
||||
SDKWrapper.getInstance().setGLSurfaceView(glSurfaceView, this);
|
||||
|
||||
|
||||
return glSurfaceView;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onResume() {
|
||||
super.onResume();
|
||||
SDKWrapper.getInstance().onResume();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onPause() {
|
||||
super.onPause();
|
||||
SDKWrapper.getInstance().onPause();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onDestroy() {
|
||||
super.onDestroy();
|
||||
SDKWrapper.getInstance().onDestroy();
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onActivityResult(int requestCode, int resultCode, Intent data) {
|
||||
super.onActivityResult(requestCode, resultCode, data);
|
||||
SDKWrapper.getInstance().onActivityResult(requestCode, resultCode, data);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onNewIntent(Intent intent) {
|
||||
super.onNewIntent(intent);
|
||||
SDKWrapper.getInstance().onNewIntent(intent);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onRestart() {
|
||||
super.onRestart();
|
||||
SDKWrapper.getInstance().onRestart();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStop() {
|
||||
super.onStop();
|
||||
SDKWrapper.getInstance().onStop();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBackPressed() {
|
||||
SDKWrapper.getInstance().onBackPressed();
|
||||
super.onBackPressed();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onConfigurationChanged(Configuration newConfig) {
|
||||
SDKWrapper.getInstance().onConfigurationChanged(newConfig);
|
||||
super.onConfigurationChanged(newConfig);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onRestoreInstanceState(Bundle savedInstanceState) {
|
||||
SDKWrapper.getInstance().onRestoreInstanceState(savedInstanceState);
|
||||
super.onRestoreInstanceState(savedInstanceState);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onSaveInstanceState(Bundle outState) {
|
||||
SDKWrapper.getInstance().onSaveInstanceState(outState);
|
||||
super.onSaveInstanceState(outState);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onStart() {
|
||||
SDKWrapper.getInstance().onStart();
|
||||
super.onStart();
|
||||
}
|
||||
|
||||
|
||||
public static void joinRoom(String teamid,String userid){
|
||||
System.out.println("run in java joinroom"+teamid+" "+userid);
|
||||
// 第四个参数是 是否检查房间存在
|
||||
api.joinChannelSingleMode(userid, teamid, 1, false);
|
||||
api.setSpeakerMute(false);
|
||||
api.setMicrophoneMute(false);
|
||||
api.setVolume(70);
|
||||
}
|
||||
|
||||
|
||||
public static void leaveRoom(){
|
||||
api.leaveChannelAll();
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void onEvent(int eventType, int errorCode, String channelID, Object param) {
|
||||
|
||||
|
||||
System.out.println("OnEvent:event " + eventType + ",error " + errorCode + ",channel " + channelID + ",param_" + param.toString());
|
||||
|
||||
|
||||
switch (eventType) {
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_OK: //YOUME_EVENT_INIT_OK:
|
||||
System.out.println("Talk 初始化成功");
|
||||
break;
|
||||
System.out.println("Talk 初始化成功");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_INIT_FAILED://YOUME_EVENT_INIT_FAILED:
|
||||
System.out.println("Talk 初始化失败");
|
||||
break;
|
||||
System.out.println("Talk 初始化失败");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_OK://YOUME_EVENT_JOIN_OK:
|
||||
System.out.println("Talk 进入频道成功,频道:" + channelID + " 用户id:" + param);
|
||||
break;
|
||||
System.out.println("Talk 进入频道成功,频道:" + channelID + " 用户id:" + param);
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_JOIN_FAILED://YOUME_EVENT_JOIN_FAILED:
|
||||
System.out.println("Talk 进入频道:" + channelID + "失败,code:" + errorCode);
|
||||
break;
|
||||
System.out.println("Talk 进入频道:" + channelID + "失败,code:" + errorCode);
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ONE://YOUME_EVENT_LEAVED_ONE:
|
||||
System.out.println("Talk 离开单个频道:" + channelID);
|
||||
break;
|
||||
System.out.println("Talk 离开单个频道:" + channelID);
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_LEAVED_ALL://YOUME_EVENT_LEAVED_ALL:
|
||||
System.out.println("Talk 离开所有频道,这个回调channel参数为空字符串");
|
||||
break;
|
||||
System.out.println("Talk 离开所有频道,这个回调channel参数为空字符串");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_PAUSED://YOUME_EVENT_PAUSED:
|
||||
System.out.println("Talk 暂停");
|
||||
break;
|
||||
System.out.println("Talk 暂停");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RESUMED://YOUME_EVENT_RESUMED:
|
||||
System.out.println("Talk 恢复");
|
||||
break;
|
||||
System.out.println("Talk 恢复");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_SUCCESS://YOUME_EVENT_SPEAK_SUCCESS:///< 切换对指定频道讲话成功(适用于多频道模式)
|
||||
break;
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_SPEAK_FAILED://YOUME_EVENT_SPEAK_FAILED:///< 切换对指定频道讲话失败(适用于多频道模式)
|
||||
break;
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTING://YOUME_EVENT_RECONNECTING:///< 断网了,正在重连
|
||||
System.out.println("Talk 正在重连");
|
||||
break;
|
||||
System.out.println("Talk 正在重连");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_RECONNECTED://YOUME_EVENT_RECONNECTED:///< 断网重连成功
|
||||
System.out.println("Talk 重连成功");
|
||||
break;
|
||||
System.out.println("Talk 重连成功");
|
||||
break;
|
||||
case YouMeConst.YouMeEvent.YOUME_EVENT_REC_PERMISSION_STATUS://YOUME_EVENT_REC_FAILED:///< 通知录音启动失败(此时不管麦克风mute状态如何,都没有声音输出)
|
||||
System.out.println("录音启动失败,code:" + errorCode);
|
||||
break;
|
||||
|
||||
System.out.println("录音启动失败,code:" + errorCode);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onRequestRestAPI(int i, int i1, String s, String s1) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onMemberChange(String s, MemberChange[] memberChanges, boolean b) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void onBroadcast(int i, String s, String s1, String s2, String s3) {
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
||||
public static void openSocialUrl(String uri){
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse(uri));
|
||||
@ -249,8 +253,11 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
||||
public static void connectwallet(String data){
|
||||
ExampleApplication.Companion.resetSession();
|
||||
ExampleApplication.session.addCallback(appActivity);
|
||||
String url = "metamask://wc?uri=" + ExampleApplication.config.toWCUri();
|
||||
Uri uri = Uri.parse(url);
|
||||
Log.i(TAG, url);
|
||||
Intent intent = new Intent(Intent.ACTION_VIEW);
|
||||
intent.setData(Uri.parse(ExampleApplication.config.toWCUri()));
|
||||
intent.setData(uri);
|
||||
try {
|
||||
appActivity.startActivity(intent);
|
||||
} catch (ActivityNotFoundException e) {
|
||||
@ -263,10 +270,38 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
||||
// private boolean hasSign = false;
|
||||
|
||||
public static void signApp(String nonce){
|
||||
ExampleApplication.Companion.ethSign(nonce,ExampleApplication.session.approvedAccounts().get(0));
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse("wc://"));
|
||||
appActivity.startActivity(i);
|
||||
Log.i(TAG, nonce);
|
||||
List<String> paramList = new ArrayList<>();
|
||||
paramList.add(ExampleApplication.session.approvedAccounts().get(0));
|
||||
paramList.add(nonce);
|
||||
long time = System.currentTimeMillis();
|
||||
|
||||
ExampleApplication.session.performMethodCall(new Session.MethodCall.Custom(time, "eth_signTypedData", paramList), new Function1<Session.MethodCall.Response, Unit>() {
|
||||
@RequiresApi(api = Build.VERSION_CODES.KITKAT)
|
||||
@Override
|
||||
public Unit invoke(Session.MethodCall.Response resp) {
|
||||
if (resp.getResult() != null) {
|
||||
String signStr = Objects.requireNonNull(resp.getResult()).toString();
|
||||
Log.i(TAG, signStr);
|
||||
signStr = signStr.substring(2);
|
||||
final String finalSignStr = signStr;
|
||||
appActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxJavascriptJavaBridge.evalString("window.signApp(\""+ finalSignStr +"\")");
|
||||
}
|
||||
});
|
||||
//
|
||||
} else {
|
||||
Log.i(TAG, "sign is empty");
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
);
|
||||
Intent i = new Intent(Intent.ACTION_VIEW);
|
||||
i.setData(Uri.parse("metamask://"));
|
||||
appActivity.startActivity(i);
|
||||
}
|
||||
|
||||
|
||||
@ -275,21 +310,21 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
||||
System.out.println("change area"+area);
|
||||
switch (area){
|
||||
case "0":
|
||||
// japan
|
||||
api.init(appKey,appSecret,9,"");
|
||||
break;
|
||||
// japan
|
||||
api.init(appKey,appSecret,9,"");
|
||||
break;
|
||||
case "1":
|
||||
//singapore
|
||||
api.init(appKey,appSecret,3,"");
|
||||
break;
|
||||
//singapore
|
||||
api.init(appKey,appSecret,3,"");
|
||||
break;
|
||||
case "2":
|
||||
// turkey
|
||||
api.init(appKey,appSecret,8,"");
|
||||
break;
|
||||
// turkey
|
||||
api.init(appKey,appSecret,8,"");
|
||||
break;
|
||||
case "3":
|
||||
// usa
|
||||
api.init(appKey,appSecret,12,"");
|
||||
break;
|
||||
// usa
|
||||
api.init(appKey,appSecret,12,"");
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@ -297,57 +332,62 @@ public class AppActivity extends Cocos2dxActivity implements YouMeCallBackInterf
|
||||
|
||||
@Override
|
||||
public void onMethodCall(@NotNull final Session.MethodCall methodCall) {
|
||||
if(ExampleApplication.session.approvedAccounts()!=null){
|
||||
if(methodCall.id()==999999999){
|
||||
//签名
|
||||
appActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String tmp = ExampleApplication.Companion.getSignRes().substring(2);
|
||||
System.out.println("签名无前缀"+tmp);
|
||||
Cocos2dxJavascriptJavaBridge.evalString("window.signApp(\""+tmp+"\")");
|
||||
}
|
||||
});
|
||||
}else{
|
||||
//连接钱包
|
||||
appActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
String result = methodCall.toString();
|
||||
String[] allRes = result.split(",");
|
||||
for(int i=0;i<allRes.length;i++){
|
||||
//删除所有空格
|
||||
String tt = allRes[i].replaceAll("\\s+", "");
|
||||
if(tt.startsWith("chainId")){
|
||||
String[] fi = tt.split("=");
|
||||
int chainid = Double.valueOf(fi[1]).intValue();
|
||||
System.out.println("chainid---"+chainid);
|
||||
if(chainid==321){
|
||||
// 链正确
|
||||
String tmp = ExampleApplication.session.approvedAccounts().get(0).substring(2);
|
||||
Cocos2dxJavascriptJavaBridge.evalString("window.connectOK(\""+tmp+"\")");
|
||||
}else{
|
||||
// 链不正确
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
final Toast toast = Toast.makeText(appActivity, "Your wallet should support KCC chain!" , Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onStatus(@NotNull Session.Status status) {
|
||||
|
||||
if (status.equals(Session.Status.Approved.INSTANCE)) {
|
||||
sessionApproved();
|
||||
} else if (status.equals(Session.Status.Closed.INSTANCE)){
|
||||
Log.i(TAG, "Session.Status.Closed");
|
||||
} else if (status.equals(Session.Status.Connected.INSTANCE)) {
|
||||
Log.i(TAG, "Session.Status.Connected");
|
||||
} else if (status.equals(Session.Status.Disconnected.INSTANCE)) {
|
||||
Log.i(TAG, "Session.Status.Disconnected");
|
||||
} else {
|
||||
// ERROR
|
||||
Log.e(TAG, "Session.Status.Error: " + status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
private void showErrMsg(final String msg) {
|
||||
runOnUiThread(new Runnable() {
|
||||
public void run() {
|
||||
final Toast toast = Toast.makeText(appActivity, msg , Toast.LENGTH_SHORT);
|
||||
toast.show();
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void sessionApproved() {
|
||||
List<String> accounts = ExampleApplication.session.approvedAccounts();
|
||||
if (accounts == null || accounts.size() == 0) {
|
||||
showErrMsg("Login failed, no account");
|
||||
return;
|
||||
}
|
||||
String account = accounts.get(0);
|
||||
if ("".equals(account) || null == account || account.length() < 2) {
|
||||
showErrMsg("Login failed, no account");
|
||||
return;
|
||||
}
|
||||
Long chainId = ((JWCSession) ExampleApplication.session).chainId();
|
||||
|
||||
if (chainId == null) {
|
||||
showErrMsg("Login failed, no chainId");
|
||||
return;
|
||||
}
|
||||
if (chainId != 321L) {
|
||||
showErrMsg("Login failed, Your wallet should support KCC chain");
|
||||
return;
|
||||
}
|
||||
|
||||
account = account.substring(2);
|
||||
final String finalAccount = account;
|
||||
appActivity.runOnGLThread(new Runnable() {
|
||||
@Override
|
||||
public void run() {
|
||||
Cocos2dxJavascriptJavaBridge.evalString("window.connectOK(\""+ finalAccount +"\")");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,12 @@
|
||||
|
||||
package org.cocos2dx.javascript;
|
||||
|
||||
import android.util.Log
|
||||
import androidx.multidex.MultiDexApplication
|
||||
import com.squareup.moshi.Moshi
|
||||
import io.walletconnect.example.server.BridgeServer
|
||||
import okhttp3.OkHttpClient
|
||||
import org.cocos2dx.javascript.wc.JWCSession
|
||||
import org.komputing.khex.extensions.toNoPrefixHexString
|
||||
import org.walletconnect.Session
|
||||
import org.walletconnect.impls.*
|
||||
@ -62,16 +64,17 @@ class ExampleApplication : MultiDexApplication() {
|
||||
session.performMethodCall(Session.MethodCall.Custom(999999999,"eth_signTypedData",parmList),::handleResponse)
|
||||
}
|
||||
|
||||
fun handleResponse(resp: Session.MethodCall.Response) {
|
||||
signRes = resp.result as String;
|
||||
fun handleResponse(resp: Session.MethodCall.Response) {
|
||||
signRes = resp.result as String
|
||||
Log.i("Application", signRes)
|
||||
}
|
||||
|
||||
|
||||
|
||||
fun resetSession() {
|
||||
nullOnThrow { session }?.clearCallbacks()
|
||||
val key = ByteArray(32).also { Random().nextBytes(it) }.toNoPrefixHexString()
|
||||
config = Session.Config(UUID.randomUUID().toString(), "https://bridge.walletconnect.org", key)
|
||||
session = WCSession(config,
|
||||
session = JWCSession(config,
|
||||
MoshiPayloadAdapter(moshi),
|
||||
storage,
|
||||
OkHttpTransport.Builder(client, moshi),
|
||||
|
@ -0,0 +1,303 @@
|
||||
package org.cocos2dx.javascript.wc
|
||||
|
||||
import org.walletconnect.Session
|
||||
import org.walletconnect.impls.WCSessionStore
|
||||
import org.walletconnect.nullOnThrow
|
||||
import org.walletconnect.types.extractSessionParams
|
||||
import org.walletconnect.types.intoMap
|
||||
import java.util.*
|
||||
import java.util.concurrent.ConcurrentHashMap
|
||||
|
||||
class JWCSession(
|
||||
private val config: Session.Config,
|
||||
private val payloadAdapter: Session.PayloadAdapter,
|
||||
private val sessionStore: WCSessionStore,
|
||||
transportBuilder: Session.Transport.Builder,
|
||||
clientMeta: Session.PeerMeta,
|
||||
clientId: String? = null
|
||||
) : Session {
|
||||
|
||||
private val keyLock = Any()
|
||||
|
||||
// Persisted state
|
||||
private var currentKey: String
|
||||
|
||||
private var approvedAccounts: List<String>? = null
|
||||
private var chainId: Long? = null
|
||||
private var handshakeId: Long? = null
|
||||
private var peerId: String? = null
|
||||
private var peerMeta: Session.PeerMeta? = null
|
||||
|
||||
private val clientData: Session.PeerData
|
||||
|
||||
// Getters
|
||||
private val encryptionKey: String
|
||||
get() = currentKey
|
||||
|
||||
private val decryptionKey: String
|
||||
get() = currentKey
|
||||
|
||||
// Non-persisted state
|
||||
private val transport = transportBuilder.build(config.bridge, ::handleStatus, ::handleMessage)
|
||||
private val requests: MutableMap<Long, (Session.MethodCall.Response) -> Unit> = ConcurrentHashMap()
|
||||
private val sessionCallbacks: MutableSet<Session.Callback> = Collections.newSetFromMap(ConcurrentHashMap<Session.Callback, Boolean>())
|
||||
|
||||
init {
|
||||
currentKey = config.key
|
||||
clientData = sessionStore.load(config.handshakeTopic)?.let {
|
||||
currentKey = it.currentKey
|
||||
approvedAccounts = it.approvedAccounts
|
||||
chainId = it.chainId
|
||||
handshakeId = it.handshakeId
|
||||
peerId = it.peerData?.id
|
||||
peerMeta = it.peerData?.meta
|
||||
if (clientId != null && clientId != it.clientData.id)
|
||||
throw IllegalArgumentException("Provided clientId is different from stored clientId")
|
||||
it.clientData
|
||||
} ?: run {
|
||||
Session.PeerData(clientId ?: UUID.randomUUID().toString(), clientMeta)
|
||||
}
|
||||
storeSession()
|
||||
}
|
||||
|
||||
override fun addCallback(cb: Session.Callback) {
|
||||
sessionCallbacks.add(cb)
|
||||
}
|
||||
|
||||
override fun removeCallback(cb: Session.Callback) {
|
||||
sessionCallbacks.remove(cb)
|
||||
}
|
||||
|
||||
override fun clearCallbacks() {
|
||||
sessionCallbacks.clear()
|
||||
}
|
||||
|
||||
private fun propagateToCallbacks(action: Session.Callback.() -> Unit) {
|
||||
sessionCallbacks.forEach {
|
||||
try { it.action() }
|
||||
catch (t: Throwable) {
|
||||
// If error propagation fails, don't try again
|
||||
nullOnThrow { it.onStatus(Session.Status.Error(t)) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun peerMeta(): Session.PeerMeta? = peerMeta
|
||||
|
||||
override fun approvedAccounts(): List<String>? = approvedAccounts
|
||||
|
||||
fun chainId(): Long? = chainId
|
||||
|
||||
override fun init() {
|
||||
if (transport.connect()) {
|
||||
// Register for all messages for this client
|
||||
transport.send(
|
||||
Session.Transport.Message(
|
||||
config.handshakeTopic, "sub", ""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun offer() {
|
||||
if (transport.connect()) {
|
||||
val requestId = createCallId()
|
||||
send(Session.MethodCall.SessionRequest(requestId, clientData), topic = config.handshakeTopic, callback = { resp ->
|
||||
// BUG in extractSessionParams, cast Double to Long error
|
||||
(resp.result as? Map<String, *>)?.extractSessionParams()?.let { params ->
|
||||
peerId = params.peerData?.id
|
||||
peerMeta = params.peerData?.meta
|
||||
approvedAccounts = params.accounts
|
||||
// chainId = params.chainId
|
||||
|
||||
val chainObj = (resp.result as Map<*, *>).get("chainId")
|
||||
var cid: Long = 0L
|
||||
if (chainObj != null) {
|
||||
cid = (chainObj as Double).toLong()
|
||||
}
|
||||
chainId = cid
|
||||
|
||||
|
||||
// chainId = ((resp.result as Map<*, *>).get("chainId") as Double).toLong()
|
||||
storeSession()
|
||||
propagateToCallbacks { onStatus(if (params.approved) Session.Status.Approved else Session.Status.Closed) }
|
||||
}
|
||||
})
|
||||
handshakeId = requestId
|
||||
}
|
||||
}
|
||||
|
||||
override fun approve(accounts: List<String>, chainId: Long) {
|
||||
val handshakeId = handshakeId ?: return
|
||||
approvedAccounts = accounts
|
||||
this.chainId = chainId
|
||||
// We should not use classes in the Response, since this will not work with proguard
|
||||
val params = Session.SessionParams(true, chainId, accounts, clientData).intoMap()
|
||||
send(Session.MethodCall.Response(handshakeId, params))
|
||||
storeSession()
|
||||
propagateToCallbacks { onStatus(Session.Status.Approved) }
|
||||
}
|
||||
|
||||
override fun update(accounts: List<String>, chainId: Long) {
|
||||
val params = Session.SessionParams(true, chainId, accounts, clientData)
|
||||
send(Session.MethodCall.SessionUpdate(createCallId(), params))
|
||||
}
|
||||
|
||||
override fun reject() {
|
||||
handshakeId?.let {
|
||||
// We should not use classes in the Response, since this will not work with proguard
|
||||
val params = Session.SessionParams(false, null, null, null).intoMap()
|
||||
send(Session.MethodCall.Response(it, params))
|
||||
}
|
||||
endSession()
|
||||
}
|
||||
|
||||
override fun approveRequest(id: Long, response: Any) {
|
||||
send(Session.MethodCall.Response(id, response))
|
||||
}
|
||||
|
||||
override fun rejectRequest(id: Long, errorCode: Long, errorMsg: String) {
|
||||
send(
|
||||
Session.MethodCall.Response(
|
||||
id,
|
||||
result = null,
|
||||
error = Session.Error(errorCode, errorMsg)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
override fun performMethodCall(call: Session.MethodCall, callback: ((Session.MethodCall.Response) -> Unit)?) {
|
||||
send(call, callback = callback)
|
||||
}
|
||||
|
||||
private fun handleStatus(status: Session.Transport.Status) {
|
||||
when (status) {
|
||||
Session.Transport.Status.Connected -> {
|
||||
// Register for all messages for this client
|
||||
transport.send(
|
||||
Session.Transport.Message(
|
||||
clientData.id, "sub", ""
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
propagateToCallbacks {
|
||||
onStatus(when(status) {
|
||||
Session.Transport.Status.Connected -> Session.Status.Connected
|
||||
Session.Transport.Status.Disconnected -> Session.Status.Disconnected
|
||||
is Session.Transport.Status.Error -> Session.Status.Error(Session.TransportError(status.throwable))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun handleMessage(message: Session.Transport.Message) {
|
||||
if (message.type != "pub") return
|
||||
val data: Session.MethodCall
|
||||
synchronized(keyLock) {
|
||||
try {
|
||||
data = payloadAdapter.parse(message.payload, decryptionKey)
|
||||
} catch (e: Exception) {
|
||||
handlePayloadError(e)
|
||||
return
|
||||
}
|
||||
}
|
||||
var accountToCheck: String? = null
|
||||
when (data) {
|
||||
is Session.MethodCall.SessionRequest -> {
|
||||
handshakeId = data.id
|
||||
peerId = data.peer.id
|
||||
peerMeta = data.peer.meta
|
||||
storeSession()
|
||||
}
|
||||
is Session.MethodCall.SessionUpdate -> {
|
||||
if (!data.params.approved) {
|
||||
endSession()
|
||||
}
|
||||
// TODO handle session update -> not important for our usecase
|
||||
}
|
||||
is Session.MethodCall.SendTransaction -> {
|
||||
accountToCheck = data.from
|
||||
}
|
||||
is Session.MethodCall.SignMessage -> {
|
||||
accountToCheck = data.address
|
||||
}
|
||||
is Session.MethodCall.Response -> {
|
||||
val callback = requests[data.id] ?: return
|
||||
callback(data)
|
||||
}
|
||||
}
|
||||
|
||||
if (accountToCheck?.let { accountCheck(data.id(), it) } != false) {
|
||||
propagateToCallbacks { onMethodCall(data) }
|
||||
}
|
||||
}
|
||||
|
||||
private fun accountCheck(id: Long, address: String): Boolean {
|
||||
approvedAccounts?.find { it.toLowerCase() == address.toLowerCase() } ?: run {
|
||||
handlePayloadError(Session.MethodCallException.InvalidAccount(id, address))
|
||||
return false
|
||||
}
|
||||
return true
|
||||
}
|
||||
|
||||
private fun handlePayloadError(e: Exception) {
|
||||
propagateToCallbacks { Session.Status.Error(e) }
|
||||
(e as? Session.MethodCallException)?.let {
|
||||
rejectRequest(it.id, it.code, it.message ?: "Unknown error")
|
||||
}
|
||||
}
|
||||
|
||||
private fun endSession() {
|
||||
sessionStore.remove(config.handshakeTopic)
|
||||
approvedAccounts = null
|
||||
chainId = null
|
||||
internalClose()
|
||||
propagateToCallbacks { onStatus(Session.Status.Closed) }
|
||||
}
|
||||
|
||||
private fun storeSession() {
|
||||
sessionStore.store(
|
||||
config.handshakeTopic,
|
||||
WCSessionStore.State(
|
||||
config,
|
||||
clientData,
|
||||
peerId?.let { Session.PeerData(it, peerMeta) },
|
||||
handshakeId,
|
||||
currentKey,
|
||||
approvedAccounts,
|
||||
chainId
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
// Returns true if method call was handed over to transport
|
||||
private fun send(
|
||||
msg: Session.MethodCall,
|
||||
topic: String? = peerId,
|
||||
callback: ((Session.MethodCall.Response) -> Unit)? = null
|
||||
): Boolean {
|
||||
topic ?: return false
|
||||
|
||||
val payload: String
|
||||
synchronized(keyLock) {
|
||||
payload = payloadAdapter.prepare(msg, encryptionKey)
|
||||
}
|
||||
callback?.let {
|
||||
requests[msg.id()] = callback
|
||||
}
|
||||
transport.send(Session.Transport.Message(topic, "pub", payload))
|
||||
return true
|
||||
}
|
||||
|
||||
private fun createCallId() = System.currentTimeMillis() * 1000 + Random().nextInt(999)
|
||||
|
||||
private fun internalClose() {
|
||||
transport.close()
|
||||
}
|
||||
|
||||
override fun kill() {
|
||||
val params = Session.SessionParams(false, null, null, null)
|
||||
send(Session.MethodCall.SessionUpdate(createCallId(), params))
|
||||
endSession()
|
||||
}
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user