Finalized Google Sign In!!!
This commit is contained in:
parent
0746a2a88e
commit
fcbce77168
7
.vscode/settings.json
vendored
Normal file
7
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
{
|
||||||
|
"files.associations": {
|
||||||
|
"*.gui_script": "lua",
|
||||||
|
"*.script": "lua",
|
||||||
|
"typeinfo": "cpp"
|
||||||
|
}
|
||||||
|
}
|
@ -1,2 +0,0 @@
|
|||||||
# C++ symbol in your extension
|
|
||||||
name: "MyExtension"
|
|
@ -1,112 +0,0 @@
|
|||||||
// myextension.cpp
|
|
||||||
// Extension lib defines
|
|
||||||
#define LIB_NAME "MyExtension"
|
|
||||||
#define MODULE_NAME "myextension"
|
|
||||||
|
|
||||||
// include the Defold SDK
|
|
||||||
#include <dmsdk/sdk.h>
|
|
||||||
|
|
||||||
static int Reverse(lua_State* L)
|
|
||||||
{
|
|
||||||
// The number of expected items to be on the Lua stack
|
|
||||||
// once this struct goes out of scope
|
|
||||||
DM_LUA_STACK_CHECK(L, 1);
|
|
||||||
|
|
||||||
// Check and get parameter string from stack
|
|
||||||
char* str = (char*)luaL_checkstring(L, 1);
|
|
||||||
|
|
||||||
// Reverse the string
|
|
||||||
int len = strlen(str);
|
|
||||||
for(int i = 0; i < len / 2; i++) {
|
|
||||||
const char a = str[i];
|
|
||||||
const char b = str[len - i - 1];
|
|
||||||
str[i] = b;
|
|
||||||
str[len - i - 1] = a;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Put the reverse string on the stack
|
|
||||||
lua_pushstring(L, str);
|
|
||||||
|
|
||||||
// Return 1 item
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Functions exposed to Lua
|
|
||||||
static const luaL_reg Module_methods[] =
|
|
||||||
{
|
|
||||||
{"reverse", Reverse},
|
|
||||||
{0, 0}
|
|
||||||
};
|
|
||||||
|
|
||||||
static void LuaInit(lua_State* L)
|
|
||||||
{
|
|
||||||
int top = lua_gettop(L);
|
|
||||||
|
|
||||||
// Register lua names
|
|
||||||
luaL_register(L, MODULE_NAME, Module_methods);
|
|
||||||
|
|
||||||
lua_pop(L, 1);
|
|
||||||
assert(top == lua_gettop(L));
|
|
||||||
}
|
|
||||||
|
|
||||||
dmExtension::Result AppInitializeMyExtension(dmExtension::AppParams* params)
|
|
||||||
{
|
|
||||||
dmLogInfo("AppInitializeMyExtension\n");
|
|
||||||
return dmExtension::RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmExtension::Result InitializeMyExtension(dmExtension::Params* params)
|
|
||||||
{
|
|
||||||
// Init Lua
|
|
||||||
LuaInit(params->m_L);
|
|
||||||
dmLogInfo("Registered %s Extension\n", MODULE_NAME);
|
|
||||||
return dmExtension::RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmExtension::Result AppFinalizeMyExtension(dmExtension::AppParams* params)
|
|
||||||
{
|
|
||||||
dmLogInfo("AppFinalizeMyExtension\n");
|
|
||||||
return dmExtension::RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmExtension::Result FinalizeMyExtension(dmExtension::Params* params)
|
|
||||||
{
|
|
||||||
dmLogInfo("FinalizeMyExtension\n");
|
|
||||||
return dmExtension::RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
dmExtension::Result OnUpdateMyExtension(dmExtension::Params* params)
|
|
||||||
{
|
|
||||||
dmLogInfo("OnUpdateMyExtension\n");
|
|
||||||
return dmExtension::RESULT_OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
void OnEventMyExtension(dmExtension::Params* params, const dmExtension::Event* event)
|
|
||||||
{
|
|
||||||
switch(event->m_Event)
|
|
||||||
{
|
|
||||||
case dmExtension::EVENT_ID_ACTIVATEAPP:
|
|
||||||
dmLogInfo("OnEventMyExtension - EVENT_ID_ACTIVATEAPP\n");
|
|
||||||
break;
|
|
||||||
case dmExtension::EVENT_ID_DEACTIVATEAPP:
|
|
||||||
dmLogInfo("OnEventMyExtension - EVENT_ID_DEACTIVATEAPP\n");
|
|
||||||
break;
|
|
||||||
case dmExtension::EVENT_ID_ICONIFYAPP:
|
|
||||||
dmLogInfo("OnEventMyExtension - EVENT_ID_ICONIFYAPP\n");
|
|
||||||
break;
|
|
||||||
case dmExtension::EVENT_ID_DEICONIFYAPP:
|
|
||||||
dmLogInfo("OnEventMyExtension - EVENT_ID_DEICONIFYAPP\n");
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
dmLogWarning("OnEventMyExtension - Unknown event id\n");
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Defold SDK uses a macro for setting up extension entry points:
|
|
||||||
//
|
|
||||||
// DM_DECLARE_EXTENSION(symbol, name, app_init, app_final, init, update, on_event, final)
|
|
||||||
|
|
||||||
// MyExtension is the C++ symbol that holds all relevant extension data.
|
|
||||||
// It must match the name field in the `ext.manifest`
|
|
||||||
DM_DECLARE_EXTENSION(MyExtension, LIB_NAME, AppInitializeMyExtension, AppFinalizeMyExtension, InitializeMyExtension, OnUpdateMyExtension, OnEventMyExtension, FinalizeMyExtension)
|
|
17
assets/main.font
Normal file
17
assets/main.font
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
font: "/builtins/fonts/vera_mo_bd.ttf"
|
||||||
|
material: "/builtins/fonts/font.material"
|
||||||
|
size: 60
|
||||||
|
antialias: 1
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 0.0
|
||||||
|
outline_width: 0.0
|
||||||
|
shadow_alpha: 0.0
|
||||||
|
shadow_blur: 0
|
||||||
|
shadow_x: 0.0
|
||||||
|
shadow_y: 0.0
|
||||||
|
extra_characters: ""
|
||||||
|
output_format: TYPE_BITMAP
|
||||||
|
all_chars: false
|
||||||
|
cache_width: 0
|
||||||
|
cache_height: 0
|
||||||
|
render_mode: MODE_SINGLE_LAYER
|
@ -3,6 +3,21 @@ scale_along_z: 0
|
|||||||
embedded_instances {
|
embedded_instances {
|
||||||
id: "go"
|
id: "go"
|
||||||
data: "components {\n"
|
data: "components {\n"
|
||||||
|
" id: \"gui\"\n"
|
||||||
|
" component: \"/example/example.gui\"\n"
|
||||||
|
" position {\n"
|
||||||
|
" x: 0.0\n"
|
||||||
|
" y: 0.0\n"
|
||||||
|
" z: 0.0\n"
|
||||||
|
" }\n"
|
||||||
|
" rotation {\n"
|
||||||
|
" x: 0.0\n"
|
||||||
|
" y: 0.0\n"
|
||||||
|
" z: 0.0\n"
|
||||||
|
" w: 1.0\n"
|
||||||
|
" }\n"
|
||||||
|
"}\n"
|
||||||
|
"components {\n"
|
||||||
" id: \"example\"\n"
|
" id: \"example\"\n"
|
||||||
" component: \"/example/example.script\"\n"
|
" component: \"/example/example.script\"\n"
|
||||||
" position {\n"
|
" position {\n"
|
||||||
|
249
example/example.gui
Normal file
249
example/example.gui
Normal file
@ -0,0 +1,249 @@
|
|||||||
|
script: "/example/example.gui_script"
|
||||||
|
fonts {
|
||||||
|
name: "main"
|
||||||
|
font: "/assets/main.font"
|
||||||
|
}
|
||||||
|
background_color {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 540.0
|
||||||
|
y: 170.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 900.0
|
||||||
|
y: 160.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: ""
|
||||||
|
id: "login_btn"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 0.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "Manual Login\n"
|
||||||
|
""
|
||||||
|
font: "main"
|
||||||
|
id: "text"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "login_btn"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 540.0
|
||||||
|
y: 427.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 900.0
|
||||||
|
y: 160.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_BOX
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
texture: ""
|
||||||
|
id: "silent_login_btn"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
slice9 {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 0.0
|
||||||
|
}
|
||||||
|
clipping_mode: CLIPPING_MODE_NONE
|
||||||
|
clipping_visible: true
|
||||||
|
clipping_inverted: false
|
||||||
|
alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
size_mode: SIZE_MODE_MANUAL
|
||||||
|
}
|
||||||
|
nodes {
|
||||||
|
position {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
rotation {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
scale {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
size {
|
||||||
|
x: 200.0
|
||||||
|
y: 100.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
color {
|
||||||
|
x: 0.0
|
||||||
|
y: 0.0
|
||||||
|
z: 0.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
type: TYPE_TEXT
|
||||||
|
blend_mode: BLEND_MODE_ALPHA
|
||||||
|
text: "Silent Login Btn"
|
||||||
|
font: "main"
|
||||||
|
id: "text1"
|
||||||
|
xanchor: XANCHOR_NONE
|
||||||
|
yanchor: YANCHOR_NONE
|
||||||
|
pivot: PIVOT_CENTER
|
||||||
|
outline {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
shadow {
|
||||||
|
x: 1.0
|
||||||
|
y: 1.0
|
||||||
|
z: 1.0
|
||||||
|
w: 1.0
|
||||||
|
}
|
||||||
|
adjust_mode: ADJUST_MODE_FIT
|
||||||
|
line_break: false
|
||||||
|
parent: "silent_login_btn"
|
||||||
|
layer: ""
|
||||||
|
inherit_alpha: true
|
||||||
|
alpha: 1.0
|
||||||
|
outline_alpha: 1.0
|
||||||
|
shadow_alpha: 1.0
|
||||||
|
template_node_child: false
|
||||||
|
text_leading: 1.0
|
||||||
|
text_tracking: 0.0
|
||||||
|
}
|
||||||
|
material: "/builtins/materials/gui.material"
|
||||||
|
adjust_reference: ADJUST_REFERENCE_PARENT
|
||||||
|
max_nodes: 512
|
52
example/example.gui_script
Normal file
52
example/example.gui_script
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
function init(self)
|
||||||
|
msg.post(".", "acquire_input_focus")
|
||||||
|
|
||||||
|
if siwg then
|
||||||
|
siwg.set_callback(gpgs_callback)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_message(self, message_id, message, sender)
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function on_input(self, action_id, action)
|
||||||
|
if action_id == hash("touch") and action.pressed then
|
||||||
|
if gui.pick_node(gui.get_node("login_btn"), action.x, action.y) then
|
||||||
|
if siwg then
|
||||||
|
print("Login Pressed!")
|
||||||
|
siwg.login()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if gui.pick_node(gui.get_node("silent_login_btn"), action.x, action.y) then
|
||||||
|
if siwg then
|
||||||
|
print("Login Pressed!")
|
||||||
|
siwg.silent_login()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function gpgs_callback(self, message_id, message)
|
||||||
|
if message_id == siwg.MSG_SIGN_IN or message_id == siwg.MSG_SILENT_SIGN_IN then
|
||||||
|
if message.status == siwg.STATUS_SUCCESS then
|
||||||
|
print("SIWG ID: " .. siwg.get_id())
|
||||||
|
print("SIWG DisplayName: " .. siwg.get_display_name())
|
||||||
|
|
||||||
|
if sys.get_config("siwg.client_id") then
|
||||||
|
print("SIWG id_token: ", siwg.get_id_token())
|
||||||
|
print("SIWG auth_code: ", siwg.get_server_auth_code())
|
||||||
|
end
|
||||||
|
|
||||||
|
elseif message.status == siwg.STATUS_FAILED then
|
||||||
|
print("Status: FAILED")
|
||||||
|
print("Error: " .. message.error)
|
||||||
|
end
|
||||||
|
elseif message_id == siwg.MSG_SIGN_OUT then
|
||||||
|
print("SIWG Logged out!")
|
||||||
|
end
|
||||||
|
|
||||||
|
print("SIWG is_logged_in: " .. tostring(siwg.is_logged_in()))
|
||||||
|
end
|
||||||
|
|
@ -1,7 +1,5 @@
|
|||||||
function init(self)
|
function init(self)
|
||||||
local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
msg.post(".", "acquire_input_focus")
|
||||||
local reverse_s = myextension.reverse(s)
|
|
||||||
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function final(self)
|
function final(self)
|
||||||
|
26
game.project
26
game.project
@ -5,12 +5,30 @@ main_collection = /example/example.collectionc
|
|||||||
shared_state = 1
|
shared_state = 1
|
||||||
|
|
||||||
[display]
|
[display]
|
||||||
width = 960
|
width = 1080
|
||||||
height = 640
|
height = 1920
|
||||||
|
|
||||||
[project]
|
[project]
|
||||||
title = SIGW-Extension
|
title = SIWG-Extension
|
||||||
|
|
||||||
[library]
|
[library]
|
||||||
include_dirs = SIGW
|
include_dirs = siwg
|
||||||
|
|
||||||
|
[native_extension]
|
||||||
|
app_manifest = /generated.appmanifest
|
||||||
|
|
||||||
|
[android]
|
||||||
|
input_method = HiddenInputField
|
||||||
|
immersive_mode = 1
|
||||||
|
package = com.aterve.partydeck
|
||||||
|
debuggable = 1
|
||||||
|
|
||||||
|
[siwg]
|
||||||
|
app_id = 715670885775
|
||||||
|
client_id = 715670885775-j3p3nr6ith9su03p2im8d2p752hptg56.apps.googleusercontent.com
|
||||||
|
request_server_auth_code = 1
|
||||||
|
request_id_token = 1
|
||||||
|
|
||||||
|
[ios]
|
||||||
|
bundle_identifier = com.aterve.partydeck
|
||||||
|
|
||||||
|
100
generated.appmanifest
Normal file
100
generated.appmanifest
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
# App manifest generated Fri Nov 20 2020 09:28:33 GMT+0100 (Central European Standard Time)
|
||||||
|
# Settings: OpenGL
|
||||||
|
platforms:
|
||||||
|
x86_64-osx:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
frameworks: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
x86_64-linux:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
js-web:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeJsLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
wasm-web:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeJsLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
x86-win32:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
x86_64-win32:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
armv7-android:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeJars: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
jetifier: true
|
||||||
|
|
||||||
|
arm64-android:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeJars: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
linkFlags: []
|
||||||
|
jetifier: true
|
||||||
|
|
||||||
|
armv7-ios:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
frameworks: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
arm64-ios:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
frameworks: []
|
||||||
|
linkFlags: []
|
||||||
|
|
||||||
|
x86_64-ios:
|
||||||
|
context:
|
||||||
|
excludeLibs: []
|
||||||
|
excludeSymbols: []
|
||||||
|
symbols: []
|
||||||
|
libs: []
|
||||||
|
frameworks: []
|
||||||
|
linkFlags: []
|
1
siwg/ext.manifest
Normal file
1
siwg/ext.manifest
Normal file
@ -0,0 +1 @@
|
|||||||
|
name: SIWG
|
7
siwg/manifests/android/AndroidManifest.xml
Normal file
7
siwg/manifests/android/AndroidManifest.xml
Normal file
@ -0,0 +1,7 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<manifest xmlns:android="http://schemas.android.com/apk/res/android" package="{{android.package}}">
|
||||||
|
<uses-sdk android:minSdkVersion="{{android.minimum_sdk_version}}" android:targetSdkVersion="{{android.target_sdk_version}}" />
|
||||||
|
<application>
|
||||||
|
<meta-data android:name="com.google.android.gms.games.APP_ID" android:value="\{{siwg.app_id}}" />
|
||||||
|
</application>
|
||||||
|
</manifest>
|
6
siwg/manifests/android/build.gradle
Normal file
6
siwg/manifests/android/build.gradle
Normal file
@ -0,0 +1,6 @@
|
|||||||
|
dependencies {
|
||||||
|
// https://developers.google.com/android/guides/setup#split
|
||||||
|
implementation 'com.google.android.gms:play-services-base:17.5.0'
|
||||||
|
implementation 'com.google.android.gms:play-services-auth:18.1.0'
|
||||||
|
implementation 'com.google.android.gms:play-services-games:20.0.1'
|
||||||
|
}
|
21
siwg/src/com_aterve_siwg_SiwgJNI.h
Normal file
21
siwg/src/com_aterve_siwg_SiwgJNI.h
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
|
||||||
|
#include <jni.h>
|
||||||
|
/* Header for class com_aterve_siwg_SiwgJNI */
|
||||||
|
|
||||||
|
#ifndef COM_ATERVE_SIWG_SIWGJNI_H
|
||||||
|
#define COM_ATERVE_SIWG_SIWGJNI_H
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* Class: com_aterve_siwg_SiwgJNI
|
||||||
|
* Method: siwgAddToQueue_first_arg
|
||||||
|
* Signature: (ILjava/lang/String;I)V
|
||||||
|
*/
|
||||||
|
JNIEXPORT void JNICALL Java_com_aterve_siwg_SiwgJNI_siwgAddToQueue
|
||||||
|
(JNIEnv *, jclass, jint, jstring);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
271
siwg/src/java/com/aterve/siwg/SiwgJNI.java
Normal file
271
siwg/src/java/com/aterve/siwg/SiwgJNI.java
Normal file
@ -0,0 +1,271 @@
|
|||||||
|
package com.aterve.siwg;
|
||||||
|
|
||||||
|
import android.app.Activity;
|
||||||
|
import android.content.Intent;
|
||||||
|
import androidx.annotation.NonNull;
|
||||||
|
import android.util.Log;
|
||||||
|
import android.view.Gravity;
|
||||||
|
|
||||||
|
import android.graphics.Bitmap;
|
||||||
|
import android.graphics.BitmapFactory;
|
||||||
|
|
||||||
|
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.api.ApiException;
|
||||||
|
import com.google.android.gms.common.ConnectionResult;
|
||||||
|
import com.google.android.gms.common.GoogleApiAvailability;
|
||||||
|
|
||||||
|
import com.google.android.gms.tasks.OnCompleteListener;
|
||||||
|
import com.google.android.gms.tasks.OnFailureListener;
|
||||||
|
import com.google.android.gms.tasks.OnSuccessListener;
|
||||||
|
import com.google.android.gms.tasks.Task;
|
||||||
|
import com.google.android.gms.tasks.Continuation;
|
||||||
|
|
||||||
|
import java.io.IOException;
|
||||||
|
|
||||||
|
import org.json.JSONArray;
|
||||||
|
import org.json.JSONObject;
|
||||||
|
import org.json.JSONException;
|
||||||
|
|
||||||
|
public class SiwgJNI {
|
||||||
|
|
||||||
|
private static final String TAG = "SiwgJNI";
|
||||||
|
|
||||||
|
// Request code used to invoke sign in user interactions.
|
||||||
|
private static final int RC_UNUSED = 5001;
|
||||||
|
private static final int RC_SIGN_IN = 9001;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Global Constants (Same as in sigw.h)
|
||||||
|
//
|
||||||
|
|
||||||
|
private static final int MSG_SIGN_IN = 1;
|
||||||
|
private static final int MSG_SILENT_SIGN_IN = 2;
|
||||||
|
private static final int MSG_SIGN_OUT = 3;
|
||||||
|
private static final int MSG_GET_EVENTS = 11;
|
||||||
|
|
||||||
|
private static final int STATUS_SUCCESS = 1;
|
||||||
|
private static final int STATUS_FAILED = 2;
|
||||||
|
private static final int STATUS_CONFLICT = 4;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Global Properties
|
||||||
|
//
|
||||||
|
|
||||||
|
private Activity activity;
|
||||||
|
private String client_id;
|
||||||
|
private boolean is_request_id_token;
|
||||||
|
private boolean is_request_auth_code;
|
||||||
|
private boolean is_supported;
|
||||||
|
|
||||||
|
//
|
||||||
|
// Client Handles
|
||||||
|
//
|
||||||
|
|
||||||
|
private GoogleSignInAccount mSignedInAccount = null;
|
||||||
|
private GoogleSignInOptions mSignInOptions;
|
||||||
|
private GoogleSignInClient mGoogleSignInClient;
|
||||||
|
|
||||||
|
// JNI Add to Queue
|
||||||
|
public static native void siwgAddToQueue(int msg, String json);
|
||||||
|
|
||||||
|
//
|
||||||
|
// Constructor
|
||||||
|
//
|
||||||
|
|
||||||
|
public SiwgJNI(Activity activity, boolean is_disk_active, boolean is_request_auth_code, boolean is_request_id_token, String client_id) {
|
||||||
|
this.activity = activity;
|
||||||
|
this.client_id = client_id;
|
||||||
|
this.is_request_auth_code = is_request_auth_code;
|
||||||
|
this.is_request_id_token = is_request_id_token;
|
||||||
|
|
||||||
|
// Check if device supports google sign in
|
||||||
|
this.is_supported = GoogleApiAvailability.getInstance().isGooglePlayServicesAvailable(activity) == ConnectionResult.SUCCESS;
|
||||||
|
|
||||||
|
// Create GoogleSignIn Client
|
||||||
|
mGoogleSignInClient = GoogleSignIn.getClient(activity, getSignInOptions());
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Event Listeners
|
||||||
|
//
|
||||||
|
|
||||||
|
private OnFailureListener newOnFailureListener(final int messageId, final String message) {
|
||||||
|
return new OnFailureListener() {
|
||||||
|
@Override
|
||||||
|
public void onFailure(@NonNull Exception e) {
|
||||||
|
sendCallbackMessage(messageId, "status", STATUS_FAILED, "error", message);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
private OnSuccessListener<Intent> newOnSuccessListenerForIntent(final int requestCode) {
|
||||||
|
return new OnSuccessListener<Intent>() {
|
||||||
|
@Override
|
||||||
|
public void onSuccess(Intent intent) {
|
||||||
|
activity.startActivityForResult(intent, requestCode);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Callback Message Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
private void sendCallbackMessage(int msg, String key_1, int value_1) {
|
||||||
|
String message = null;
|
||||||
|
try {
|
||||||
|
JSONObject obj = new JSONObject();
|
||||||
|
obj.put(key_1, value_1);
|
||||||
|
message = obj.toString();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
message = "{ \"error\": \"Error while converting callback message to JSON: " + e.getMessage() + "\" }";
|
||||||
|
}
|
||||||
|
siwgAddToQueue(msg, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCallbackMessage(int msg, String key_1, int value_1, String key_2, String value_2) {
|
||||||
|
String message = null;
|
||||||
|
try {
|
||||||
|
JSONObject obj = new JSONObject();
|
||||||
|
obj.put(key_1, value_1);
|
||||||
|
obj.put(key_2, value_2);
|
||||||
|
message = obj.toString();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
message = "{ \"error\": \"Error while converting callback message to JSON: " + e.getMessage() + "\" }";
|
||||||
|
}
|
||||||
|
siwgAddToQueue(msg, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void sendCallbackMessage(int msg, String key_1, int value_1, String key_2, int value_2, String key_3, String value_3) {
|
||||||
|
String message = null;
|
||||||
|
try {
|
||||||
|
JSONObject obj = new JSONObject();
|
||||||
|
obj.put(key_1, value_1);
|
||||||
|
obj.put(key_2, value_2);
|
||||||
|
obj.put(key_3, value_3);
|
||||||
|
message = obj.toString();
|
||||||
|
} catch (JSONException e) {
|
||||||
|
message = "{ \"error\": \"Error while converting callback message to JSON: " + e.getMessage() + "\" }";
|
||||||
|
}
|
||||||
|
siwgAddToQueue(msg, message);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void onConnected(GoogleSignInAccount googleSignInAccount, final int msg) {
|
||||||
|
if (mSignedInAccount != googleSignInAccount) {
|
||||||
|
mSignedInAccount = googleSignInAccount;
|
||||||
|
sendCallbackMessage(msg, "status", STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private GoogleSignInOptions getSignInOptions() {
|
||||||
|
if (mSignInOptions == null) {
|
||||||
|
|
||||||
|
// Create Google Sign in (Default)
|
||||||
|
GoogleSignInOptions.Builder builder = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN);
|
||||||
|
|
||||||
|
if (is_request_id_token && client_id != null) {
|
||||||
|
builder.requestIdToken(client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_request_auth_code && client_id != null) {
|
||||||
|
builder.requestServerAuthCode(client_id);
|
||||||
|
}
|
||||||
|
|
||||||
|
mSignInOptions = builder.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
return mSignInOptions;
|
||||||
|
}
|
||||||
|
|
||||||
|
public void activityResult(int requestCode, int resultCode, Intent intent) {
|
||||||
|
if (requestCode == RC_SIGN_IN) {
|
||||||
|
if (intent != null) {
|
||||||
|
Task<GoogleSignInAccount> task = GoogleSignIn.getSignedInAccountFromIntent(intent);
|
||||||
|
|
||||||
|
if (task.isSuccessful()) {
|
||||||
|
onConnected(task.getResult(), MSG_SIGN_IN);
|
||||||
|
} else {
|
||||||
|
sendCallbackMessage(MSG_SIGN_IN, "status", STATUS_FAILED, "error", "SIWG Sign-in Failed. Task Not Successfull!");
|
||||||
|
}
|
||||||
|
|
||||||
|
} else {
|
||||||
|
sendCallbackMessage(MSG_SIGN_IN, "status", STATUS_FAILED, "error", "SIWG Sign-in Failed. Intent does not exist!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
public void silentLogin() {
|
||||||
|
this.activity.runOnUiThread(new Runnable() {
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
|
||||||
|
GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(activity);
|
||||||
|
|
||||||
|
if (GoogleSignIn.hasPermissions(account, getSignInOptions().getScopeArray())) {
|
||||||
|
onConnected(account, MSG_SILENT_SIGN_IN);
|
||||||
|
} else {
|
||||||
|
|
||||||
|
mGoogleSignInClient.silentSignIn().addOnCompleteListener(activity,
|
||||||
|
new OnCompleteListener<GoogleSignInAccount>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(@NonNull Task<GoogleSignInAccount> task) {
|
||||||
|
if (task.isSuccessful()) {
|
||||||
|
onConnected(task.getResult(), MSG_SILENT_SIGN_IN);
|
||||||
|
} else {
|
||||||
|
sendCallbackMessage(MSG_SILENT_SIGN_IN, "status", STATUS_FAILED, "error", "SIWG Silent Sign-in Failed.");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JNI Passed Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
public void login() {
|
||||||
|
Intent intent = mGoogleSignInClient.getSignInIntent();
|
||||||
|
this.activity.startActivityForResult(intent, RC_SIGN_IN);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void logout() {
|
||||||
|
mGoogleSignInClient.signOut().addOnCompleteListener(this.activity,
|
||||||
|
new OnCompleteListener<Void>() {
|
||||||
|
@Override
|
||||||
|
public void onComplete(@NonNull Task<Void> task) {
|
||||||
|
mSignedInAccount = null;
|
||||||
|
sendCallbackMessage(MSG_SIGN_OUT, "status", STATUS_SUCCESS);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getDisplayName() {
|
||||||
|
return isLoggedIn() ? mSignedInAccount.getDisplayName() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getId() {
|
||||||
|
return isLoggedIn() ? mSignedInAccount.getId() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getIdToken() {
|
||||||
|
return isLoggedIn() ? mSignedInAccount.getIdToken() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public String getServerAuthCode() {
|
||||||
|
return isLoggedIn() ? mSignedInAccount.getServerAuthCode() : null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isLoggedIn() {
|
||||||
|
return mSignedInAccount != null;
|
||||||
|
}
|
||||||
|
|
||||||
|
public boolean isSupported() {
|
||||||
|
return is_supported;
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
24
siwg/src/private_siwg_callback.h
Normal file
24
siwg/src/private_siwg_callback.h
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <dmsdk/sdk.h>
|
||||||
|
#include "siwg.h"
|
||||||
|
|
||||||
|
struct SIWG_callback
|
||||||
|
{
|
||||||
|
SIWG_callback() : m_L(0), m_Callback(LUA_NOREF), m_Self(LUA_NOREF) {}
|
||||||
|
lua_State* m_L;
|
||||||
|
int m_Callback;
|
||||||
|
int m_Self;
|
||||||
|
};
|
||||||
|
|
||||||
|
struct CallbackData
|
||||||
|
{
|
||||||
|
MESSAGE_ID msg;
|
||||||
|
char* json;
|
||||||
|
};
|
||||||
|
|
||||||
|
void siwg_set_callback(lua_State* L, int pos);
|
||||||
|
void siwg_callback_initialize();
|
||||||
|
void siwg_callback_finalize();
|
||||||
|
void siwg_callback_update();
|
||||||
|
void siwg_add_to_queue(MESSAGE_ID msg, const char*json);
|
403
siwg/src/siwg.cpp
Normal file
403
siwg/src/siwg.cpp
Normal file
@ -0,0 +1,403 @@
|
|||||||
|
#define EXTENSION_NAME SIWG
|
||||||
|
#define LIB_NAME "SIWG"
|
||||||
|
#define MODULE_NAME "siwg"
|
||||||
|
|
||||||
|
// include the Defold SDK
|
||||||
|
#include <dmsdk/sdk.h>
|
||||||
|
|
||||||
|
#if defined(DM_PLATFORM_ANDROID)
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
|
||||||
|
#include "siwg.h"
|
||||||
|
#include "siwg_jni.h"
|
||||||
|
#include "private_siwg_callback.h"
|
||||||
|
#include "com_aterve_siwg_SiwgJNI.h"
|
||||||
|
|
||||||
|
static bool luaL_checkbool(lua_State *L, int numArg)
|
||||||
|
{
|
||||||
|
bool b = false;
|
||||||
|
if (lua_isboolean(L, numArg))
|
||||||
|
{
|
||||||
|
b = lua_toboolean(L, numArg);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
luaL_typerror(L, numArg, lua_typename(L, LUA_TBOOLEAN));
|
||||||
|
}
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool luaL_checkboold(lua_State *L, int numArg, int def)
|
||||||
|
{
|
||||||
|
int type = lua_type(L, numArg);
|
||||||
|
if (type != LUA_TNONE && type != LUA_TNIL)
|
||||||
|
{
|
||||||
|
return luaL_checkbool(L, numArg);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lua_Number luaL_checknumberd(lua_State *L, int numArg, lua_Number def)
|
||||||
|
{
|
||||||
|
int type = lua_type(L, numArg);
|
||||||
|
if (type != LUA_TNONE && type != LUA_TNIL)
|
||||||
|
{
|
||||||
|
return luaL_checknumber(L, numArg);
|
||||||
|
}
|
||||||
|
return def;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* luaL_checkstringd(lua_State *L, int numArg, const char* def)
|
||||||
|
{
|
||||||
|
int type = lua_type(L, numArg);
|
||||||
|
if (type != LUA_TNONE && type != LUA_TNIL)
|
||||||
|
{
|
||||||
|
return (char*)luaL_checkstring(L, numArg);
|
||||||
|
}
|
||||||
|
return (char*)def;
|
||||||
|
}
|
||||||
|
|
||||||
|
static lua_Number luaL_checktable_number(lua_State *L, int numArg, const char* field, lua_Number def)
|
||||||
|
{
|
||||||
|
lua_Number result = def;
|
||||||
|
if(lua_istable(L, numArg))
|
||||||
|
{
|
||||||
|
lua_getfield(L, numArg, field);
|
||||||
|
if(!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
result = luaL_checknumber(L, -1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char* luaL_checktable_string(lua_State *L, int numArg, const char* field, char* def)
|
||||||
|
{
|
||||||
|
char* result = def;
|
||||||
|
if(lua_istable(L, numArg))
|
||||||
|
{
|
||||||
|
lua_getfield(L, numArg, field);
|
||||||
|
if(!lua_isnil(L, -1))
|
||||||
|
{
|
||||||
|
result = (char*)luaL_checkstring(L, -1);
|
||||||
|
}
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// JNI Method Executors
|
||||||
|
//
|
||||||
|
|
||||||
|
// void method()
|
||||||
|
static int CallVoidMethod(jobject instance, jmethodID method)
|
||||||
|
{
|
||||||
|
ThreadAttacher attacher;
|
||||||
|
JNIEnv *env = attacher.env;
|
||||||
|
env->CallVoidMethod(instance, method);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
// string method()
|
||||||
|
static int CallStringMethod(lua_State* L, jobject instance, jmethodID method)
|
||||||
|
{
|
||||||
|
DM_LUA_STACK_CHECK(L, 1);
|
||||||
|
ThreadAttacher attacher;
|
||||||
|
JNIEnv *env = attacher.env;
|
||||||
|
jstring return_value = (jstring)env->CallObjectMethod(instance, method);
|
||||||
|
if (return_value)
|
||||||
|
{
|
||||||
|
const char* cstr = env->GetStringUTFChars(return_value, 0);
|
||||||
|
lua_pushstring(L, cstr);
|
||||||
|
env->ReleaseStringUTFChars(return_value, cstr);
|
||||||
|
env->DeleteLocalRef(return_value);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
lua_pushnil(L);
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
// boolean method()
|
||||||
|
static int CallBooleanMethod(lua_State* L, jobject instance, jmethodID method)
|
||||||
|
{
|
||||||
|
DM_LUA_STACK_CHECK(L, 1);
|
||||||
|
ThreadAttacher attacher;
|
||||||
|
JNIEnv *env = attacher.env;
|
||||||
|
jboolean return_value = (jboolean)env->CallBooleanMethod(instance, method);
|
||||||
|
lua_pushboolean(L, JNI_TRUE == return_value);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// SIWG Handler
|
||||||
|
//
|
||||||
|
|
||||||
|
struct SIWG
|
||||||
|
{
|
||||||
|
jobject m_SiwgJNI;
|
||||||
|
jmethodID m_silentLogin;
|
||||||
|
jmethodID m_login;
|
||||||
|
jmethodID m_logout;
|
||||||
|
jmethodID m_activityResult;
|
||||||
|
jmethodID m_getDisplayName;
|
||||||
|
jmethodID m_getId;
|
||||||
|
jmethodID m_getIdToken;
|
||||||
|
jmethodID m_getServerAuthCode;
|
||||||
|
jmethodID m_isLoggedIn;
|
||||||
|
jmethodID m_isSupported;
|
||||||
|
};
|
||||||
|
|
||||||
|
static SIWG g_siwg;
|
||||||
|
|
||||||
|
static int SiwgAuth_Login(lua_State* L)
|
||||||
|
{
|
||||||
|
CallVoidMethod(g_siwg.m_SiwgJNI, g_siwg.m_login);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_Logout(lua_State* L)
|
||||||
|
{
|
||||||
|
CallVoidMethod(g_siwg.m_SiwgJNI, g_siwg.m_logout);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_SilentLogin(lua_State* L)
|
||||||
|
{
|
||||||
|
CallVoidMethod(g_siwg.m_SiwgJNI, g_siwg.m_silentLogin);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_getDisplayName(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallStringMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_getDisplayName);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_getId(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallStringMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_getId);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_getIdToken(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallStringMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_getIdToken);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_getServerAuthCode(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallStringMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_getServerAuthCode);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_isLoggedIn(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallBooleanMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_isLoggedIn);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_isSupported(lua_State* L)
|
||||||
|
{
|
||||||
|
return CallBooleanMethod(L, g_siwg.m_SiwgJNI, g_siwg.m_isSupported);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int SiwgAuth_set_callback(lua_State* L)
|
||||||
|
{
|
||||||
|
siwg_set_callback(L, 1);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JNI Extension Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
static void OnActivityResult(void *env, void* activity, int32_t request_code, int32_t result_code, void* result)
|
||||||
|
{
|
||||||
|
ThreadAttacher attacher;
|
||||||
|
JNIEnv *_env = attacher.env;
|
||||||
|
|
||||||
|
_env->CallVoidMethod(g_siwg.m_SiwgJNI, g_siwg.m_activityResult, request_code, result_code, result);
|
||||||
|
}
|
||||||
|
|
||||||
|
JNIEXPORT void JNICALL Java_com_aterve_siwg_SiwgJNI_siwgAddToQueue(JNIEnv * env, jclass cls, jint jmsg, jstring jjson)
|
||||||
|
{
|
||||||
|
const char* json = env->GetStringUTFChars(jjson, 0);
|
||||||
|
siwg_add_to_queue((MESSAGE_ID)jmsg, json);
|
||||||
|
env->ReleaseStringUTFChars(jjson, json);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Functions exposed to Lua
|
||||||
|
static const luaL_reg Siwg_methods[] =
|
||||||
|
{
|
||||||
|
{"is_supported", SiwgAuth_isSupported},
|
||||||
|
{"login", SiwgAuth_Login},
|
||||||
|
{"logout", SiwgAuth_Logout},
|
||||||
|
{"silent_login", SiwgAuth_SilentLogin},
|
||||||
|
{"get_display_name", SiwgAuth_getDisplayName},
|
||||||
|
{"get_id", SiwgAuth_getId},
|
||||||
|
{"get_id_token", SiwgAuth_getIdToken},
|
||||||
|
{"get_server_auth_code", SiwgAuth_getServerAuthCode},
|
||||||
|
{"is_logged_in", SiwgAuth_isLoggedIn},
|
||||||
|
{"set_callback", SiwgAuth_set_callback},
|
||||||
|
{0, 0}
|
||||||
|
};
|
||||||
|
|
||||||
|
dmExtension::Result AppInitializeSIWG(dmExtension::AppParams* params)
|
||||||
|
{
|
||||||
|
dmLogInfo("[SIWG] Registered Extension!");
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void LuaInit(lua_State* L)
|
||||||
|
{
|
||||||
|
DM_LUA_STACK_CHECK(L, 0);
|
||||||
|
luaL_register(L, MODULE_NAME, Siwg_methods);
|
||||||
|
|
||||||
|
#define SETCONSTANT(name) \
|
||||||
|
lua_pushnumber(L, (lua_Number) name); \
|
||||||
|
lua_setfield(L, -2, #name); \
|
||||||
|
|
||||||
|
SETCONSTANT(MSG_SIGN_IN)
|
||||||
|
SETCONSTANT(MSG_SILENT_SIGN_IN)
|
||||||
|
SETCONSTANT(MSG_SIGN_OUT)
|
||||||
|
|
||||||
|
SETCONSTANT(STATUS_SUCCESS)
|
||||||
|
SETCONSTANT(STATUS_FAILED)
|
||||||
|
SETCONSTANT(STATUS_CONFLICT)
|
||||||
|
#undef SETCONSTANT
|
||||||
|
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// JNI Setup Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
static void InitJNIMethods(JNIEnv* env, jclass cls)
|
||||||
|
{
|
||||||
|
//general
|
||||||
|
g_siwg.m_isSupported = env->GetMethodID(cls, "isSupported", "()Z");
|
||||||
|
|
||||||
|
//authorization
|
||||||
|
g_siwg.m_silentLogin = env->GetMethodID(cls, "silentLogin", "()V");
|
||||||
|
g_siwg.m_login = env->GetMethodID(cls, "login", "()V");
|
||||||
|
g_siwg.m_logout = env->GetMethodID(cls, "logout", "()V");
|
||||||
|
g_siwg.m_isLoggedIn = env->GetMethodID(cls, "isLoggedIn", "()Z");
|
||||||
|
g_siwg.m_getDisplayName = env->GetMethodID(cls, "getDisplayName", "()Ljava/lang/String;");
|
||||||
|
g_siwg.m_getId = env->GetMethodID(cls, "getId", "()Ljava/lang/String;");
|
||||||
|
g_siwg.m_getIdToken = env->GetMethodID(cls, "getIdToken", "()Ljava/lang/String;");
|
||||||
|
g_siwg.m_getServerAuthCode = env->GetMethodID(cls, "getServerAuthCode", "()Ljava/lang/String;");
|
||||||
|
|
||||||
|
//private methods
|
||||||
|
g_siwg.m_activityResult = env->GetMethodID(cls, "activityResult", "(IILandroid/content/Intent;)V");
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static void CheckInitializationParams(const char* client_id, bool request_server_auth_code, bool request_id_token)
|
||||||
|
{
|
||||||
|
bool is_empty_client_id = client_id == 0 || strlen(client_id) == 0;
|
||||||
|
|
||||||
|
if (is_empty_client_id && request_server_auth_code)
|
||||||
|
{
|
||||||
|
dmLogError("'siwg.client_id' must be defined to request server auth code!");
|
||||||
|
}
|
||||||
|
|
||||||
|
if (is_empty_client_id && request_id_token)
|
||||||
|
{
|
||||||
|
dmLogError("'siwg.client_id' must be defined to request id token!");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void InitializeJNI(const char* client_id, bool request_server_auth_code, bool request_id_token)
|
||||||
|
{
|
||||||
|
CheckInitializationParams(client_id, request_server_auth_code > 0, request_id_token > 0);
|
||||||
|
dmLogInfo("[SIWG] InitJNI Checked Params");
|
||||||
|
|
||||||
|
ThreadAttacher attacher;
|
||||||
|
JNIEnv *env = attacher.env;
|
||||||
|
ClassLoader class_loader = ClassLoader(env);
|
||||||
|
jclass cls = class_loader.load("com.aterve.siwg.SiwgJNI");
|
||||||
|
dmLogInfo("[SIWG] InitJNI Loaded Class");
|
||||||
|
|
||||||
|
InitJNIMethods(env, cls);
|
||||||
|
dmLogInfo("[SIWG] InitJNI Methods Initialized");
|
||||||
|
|
||||||
|
jmethodID jni_constructor = env->GetMethodID(cls, "<init>", "(Landroid/app/Activity;ZZZLjava/lang/String;)V");
|
||||||
|
jstring java_client_id = env->NewStringUTF(client_id);
|
||||||
|
|
||||||
|
g_siwg.m_SiwgJNI = env->NewGlobalRef(env->NewObject(cls, jni_constructor, dmGraphics::GetNativeAndroidActivity(), true, request_server_auth_code, request_id_token, java_client_id));
|
||||||
|
env->DeleteLocalRef(java_client_id);
|
||||||
|
dmLogInfo("[SIWG] InitJNI JNI Refrences Initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
//
|
||||||
|
// Extention Event Methods
|
||||||
|
//
|
||||||
|
|
||||||
|
dmExtension::Result InitializeSIWG(dmExtension::Params* params)
|
||||||
|
{
|
||||||
|
dmLogInfo("[SIWG] Initializing Extension...");
|
||||||
|
|
||||||
|
LuaInit(params->m_L);
|
||||||
|
int request_server_auth_code = dmConfigFile::GetInt(params->m_ConfigFile, "siwg.request_server_auth_code", 0);
|
||||||
|
int request_id_token = dmConfigFile::GetInt(params->m_ConfigFile, "siwg.request_id_token", 0);
|
||||||
|
const char* client_id = dmConfigFile::GetString(params->m_ConfigFile, "siwg.client_id", 0);
|
||||||
|
dmLogInfo("[SIWG] Loaded Settings");
|
||||||
|
|
||||||
|
InitializeJNI(client_id, request_server_auth_code > 0, request_id_token > 0);
|
||||||
|
|
||||||
|
dmExtension::RegisterAndroidOnActivityResultListener(OnActivityResult);
|
||||||
|
dmLogInfo("[SIWG] Activity Result Listener Initialized");
|
||||||
|
|
||||||
|
siwg_callback_initialize();
|
||||||
|
|
||||||
|
dmLogInfo("[SIWG] Initialization Completed!");
|
||||||
|
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmExtension::Result UpdateSIWG(dmExtension::Params* params)
|
||||||
|
{
|
||||||
|
siwg_callback_update();
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmExtension::Result FinalizeSIWG(dmExtension::Params* params)
|
||||||
|
{
|
||||||
|
dmLogInfo("[SIWG] Finalizing Extension...");
|
||||||
|
|
||||||
|
siwg_callback_finalize();
|
||||||
|
|
||||||
|
dmExtension::UnregisterAndroidOnActivityResultListener(OnActivityResult);
|
||||||
|
dmLogInfo("[SIWG] Activity Result Listener Unregistered");
|
||||||
|
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmExtension::Result AppFinalizeSIWG(dmExtension::AppParams* params)
|
||||||
|
{
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, AppInitializeSIWG, AppFinalizeSIWG, InitializeSIWG, UpdateSIWG, 0, FinalizeSIWG)
|
||||||
|
|
||||||
|
#else
|
||||||
|
|
||||||
|
dmExtension::Result InitializeSIWG(dmExtension::Params* params)
|
||||||
|
{
|
||||||
|
dmLogInfo("[SIWG] Initializing Extension...");
|
||||||
|
dmLogInfo("[SIWG] Initialization Failed! (Invalid OS Type)");
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
dmExtension::Result FinalizeSIWG(dmExtension::Params* params)
|
||||||
|
{
|
||||||
|
dmLogInfo("[SIWG] Finalizing Extension...");
|
||||||
|
return dmExtension::RESULT_OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
DM_DECLARE_EXTENSION(EXTENSION_NAME, LIB_NAME, 0, 0, InitializeSIWG, 0, 0, FinalizeSIWG)
|
||||||
|
|
||||||
|
#endif
|
17
siwg/src/siwg.h
Normal file
17
siwg/src/siwg.h
Normal file
@ -0,0 +1,17 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
// Internal to the extension
|
||||||
|
enum MESSAGE_ID
|
||||||
|
{
|
||||||
|
MSG_SIGN_IN = 1,
|
||||||
|
MSG_SILENT_SIGN_IN = 2,
|
||||||
|
MSG_SIGN_OUT = 3,
|
||||||
|
};
|
||||||
|
|
||||||
|
// Internal to the extension
|
||||||
|
enum STATUS
|
||||||
|
{
|
||||||
|
STATUS_SUCCESS = 1,
|
||||||
|
STATUS_FAILED = 2,
|
||||||
|
STATUS_CONFLICT = 4,
|
||||||
|
};
|
157
siwg/src/siwg_callback.cpp
Normal file
157
siwg/src/siwg_callback.cpp
Normal file
@ -0,0 +1,157 @@
|
|||||||
|
#if defined(DM_PLATFORM_IOS) || defined(DM_PLATFORM_ANDROID)
|
||||||
|
#include "private_siwg_callback.h"
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
static SIWG_callback m_callback;
|
||||||
|
static dmArray<CallbackData> m_callbacksQueue;
|
||||||
|
static dmMutex::HMutex m_mutex;
|
||||||
|
|
||||||
|
static void RegisterCallback(lua_State* L, int index)
|
||||||
|
{
|
||||||
|
SIWG_callback *cbk = &m_callback;
|
||||||
|
if(cbk->m_Callback != LUA_NOREF)
|
||||||
|
{
|
||||||
|
dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Callback);
|
||||||
|
dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Self);
|
||||||
|
}
|
||||||
|
|
||||||
|
cbk->m_L = dmScript::GetMainThread(L);
|
||||||
|
|
||||||
|
luaL_checktype(L, index, LUA_TFUNCTION);
|
||||||
|
lua_pushvalue(L, index);
|
||||||
|
cbk->m_Callback = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
||||||
|
|
||||||
|
dmScript::GetInstance(L);
|
||||||
|
cbk->m_Self = dmScript::Ref(L, LUA_REGISTRYINDEX);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void UnregisterCallback()
|
||||||
|
{
|
||||||
|
SIWG_callback *cbk = &m_callback;
|
||||||
|
if(cbk->m_Callback != LUA_NOREF)
|
||||||
|
{
|
||||||
|
dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Callback);
|
||||||
|
dmScript::Unref(cbk->m_L, LUA_REGISTRYINDEX, cbk->m_Self);
|
||||||
|
cbk->m_Callback = LUA_NOREF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static void siwg_invoke_callback(MESSAGE_ID type, char*json)
|
||||||
|
{
|
||||||
|
SIWG_callback *cbk = &m_callback;
|
||||||
|
if(cbk->m_Callback == LUA_NOREF)
|
||||||
|
{
|
||||||
|
dmLogInfo("GPGS callback do not exist.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
lua_State* L = cbk->m_L;
|
||||||
|
int top = lua_gettop(L);
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, cbk->m_Callback);
|
||||||
|
lua_rawgeti(L, LUA_REGISTRYINDEX, cbk->m_Self);
|
||||||
|
lua_pushvalue(L, -1);
|
||||||
|
dmScript::SetInstance(L);
|
||||||
|
|
||||||
|
if (!dmScript::IsInstanceValid(L))
|
||||||
|
{
|
||||||
|
UnregisterCallback();
|
||||||
|
dmLogError("Could not run GPGS callback because the instance has been deleted.");
|
||||||
|
lua_pop(L, 2);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
lua_pushnumber(L, type);
|
||||||
|
int count_table_elements = 1;
|
||||||
|
bool is_fail = false;
|
||||||
|
dmJson::Document doc;
|
||||||
|
dmJson::Result r = dmJson::Parse(json, &doc);
|
||||||
|
if (r == dmJson::RESULT_OK && doc.m_NodeCount > 0) {
|
||||||
|
char error_str_out[128];
|
||||||
|
if (dmScript::JsonToLua(L, &doc, 0, error_str_out, sizeof(error_str_out)) < 0) {
|
||||||
|
dmLogError("Failed converting object JSON to Lua; %s", error_str_out);
|
||||||
|
is_fail = true;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
dmLogError("Failed to parse JSON object(%d): (%s)", r, json);
|
||||||
|
is_fail = true;
|
||||||
|
}
|
||||||
|
dmJson::Free(&doc);
|
||||||
|
if (is_fail) {
|
||||||
|
lua_pop(L, 2);
|
||||||
|
assert(top == lua_gettop(L));
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
int number_of_arguments = 3;
|
||||||
|
int ret = lua_pcall(L, number_of_arguments, 0, 0);
|
||||||
|
if(ret != 0)
|
||||||
|
{
|
||||||
|
dmLogError("Error running callback: %s", lua_tostring(L, -1));
|
||||||
|
lua_pop(L, 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
assert(top == lua_gettop(L));
|
||||||
|
}
|
||||||
|
|
||||||
|
void siwg_callback_initialize()
|
||||||
|
{
|
||||||
|
m_mutex = dmMutex::New();
|
||||||
|
dmLogInfo("[SIWG] Callback initialized");
|
||||||
|
}
|
||||||
|
|
||||||
|
void siwg_callback_finalize()
|
||||||
|
{
|
||||||
|
dmMutex::Delete(m_mutex);
|
||||||
|
UnregisterCallback();
|
||||||
|
dmLogInfo("[SIWG] Callback Unregistered");
|
||||||
|
}
|
||||||
|
|
||||||
|
void siwg_set_callback(lua_State* L, int pos)
|
||||||
|
{
|
||||||
|
int type = lua_type(L, pos);
|
||||||
|
if (type == LUA_TNONE || type == LUA_TNIL)
|
||||||
|
{
|
||||||
|
UnregisterCallback();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
RegisterCallback(L, pos);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void siwg_add_to_queue(MESSAGE_ID msg, const char*json)
|
||||||
|
{
|
||||||
|
DM_MUTEX_SCOPED_LOCK(m_mutex);
|
||||||
|
|
||||||
|
CallbackData data;
|
||||||
|
data.msg = msg;
|
||||||
|
data.json = json ? strdup(json) : NULL;
|
||||||
|
|
||||||
|
if(m_callbacksQueue.Full())
|
||||||
|
{
|
||||||
|
m_callbacksQueue.OffsetCapacity(1);
|
||||||
|
}
|
||||||
|
m_callbacksQueue.Push(data);
|
||||||
|
}
|
||||||
|
|
||||||
|
void siwg_callback_update()
|
||||||
|
{
|
||||||
|
if (m_callbacksQueue.Empty())
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
DM_MUTEX_SCOPED_LOCK(m_mutex);
|
||||||
|
|
||||||
|
for(uint32_t i = 0; i != m_callbacksQueue.Size(); ++i)
|
||||||
|
{
|
||||||
|
CallbackData* data = &m_callbacksQueue[i];
|
||||||
|
siwg_invoke_callback(data->msg, data->json);
|
||||||
|
if(data->json)
|
||||||
|
{
|
||||||
|
free(data->json);
|
||||||
|
data->json = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
m_callbacksQueue.SetSize(0);
|
||||||
|
}
|
||||||
|
#endif
|
54
siwg/src/siwg_jni.h
Normal file
54
siwg/src/siwg_jni.h
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(DM_PLATFORM_ANDROID)
|
||||||
|
|
||||||
|
#include <dmsdk/sdk.h>
|
||||||
|
#include <jni.h>
|
||||||
|
|
||||||
|
struct ThreadAttacher {
|
||||||
|
JNIEnv *env;
|
||||||
|
bool has_attached;
|
||||||
|
ThreadAttacher() : env(NULL), has_attached(false) {
|
||||||
|
if (dmGraphics::GetNativeAndroidJavaVM()->GetEnv((void **)&env, JNI_VERSION_1_6) != JNI_OK) {
|
||||||
|
dmGraphics::GetNativeAndroidJavaVM()->AttachCurrentThread(&env, NULL);
|
||||||
|
has_attached = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
~ThreadAttacher() {
|
||||||
|
if (has_attached) {
|
||||||
|
if (env->ExceptionCheck()) {
|
||||||
|
env->ExceptionDescribe();
|
||||||
|
}
|
||||||
|
env->ExceptionClear();
|
||||||
|
dmGraphics::GetNativeAndroidJavaVM()->DetachCurrentThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
struct ClassLoader {
|
||||||
|
private:
|
||||||
|
JNIEnv *env;
|
||||||
|
jobject class_loader_object;
|
||||||
|
jmethodID find_class;
|
||||||
|
public:
|
||||||
|
ClassLoader(JNIEnv *env) : env(env) {
|
||||||
|
jclass activity_class = env->FindClass("android/app/NativeActivity");
|
||||||
|
jmethodID get_class_loader = env->GetMethodID(activity_class, "getClassLoader", "()Ljava/lang/ClassLoader;");
|
||||||
|
class_loader_object = env->CallObjectMethod(dmGraphics::GetNativeAndroidActivity(), get_class_loader);
|
||||||
|
jclass class_loader = env->FindClass("java/lang/ClassLoader");
|
||||||
|
find_class = env->GetMethodID(class_loader, "loadClass", "(Ljava/lang/String;)Ljava/lang/Class;");
|
||||||
|
env->DeleteLocalRef(activity_class);
|
||||||
|
env->DeleteLocalRef(class_loader);
|
||||||
|
}
|
||||||
|
~ClassLoader() {
|
||||||
|
env->DeleteLocalRef(class_loader_object);
|
||||||
|
}
|
||||||
|
jclass load(const char *class_name) {
|
||||||
|
jstring str_class_name = env->NewStringUTF(class_name);
|
||||||
|
jclass loaded_class = (jclass)env->CallObjectMethod(class_loader_object, find_class, str_class_name);
|
||||||
|
env->DeleteLocalRef(str_class_name);
|
||||||
|
return loaded_class;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
Loading…
x
Reference in New Issue
Block a user