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 {
|
||||
id: "go"
|
||||
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"
|
||||
" component: \"/example/example.script\"\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)
|
||||
local s = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ"
|
||||
local reverse_s = myextension.reverse(s)
|
||||
print(reverse_s) --> ZYXWVUTSRQPONMLKJIHGFEDCBAzyxwvutsrqponmlkjihgfedcba
|
||||
msg.post(".", "acquire_input_focus")
|
||||
end
|
||||
|
||||
function final(self)
|
||||
|
26
game.project
26
game.project
@ -5,12 +5,30 @@ main_collection = /example/example.collectionc
|
||||
shared_state = 1
|
||||
|
||||
[display]
|
||||
width = 960
|
||||
height = 640
|
||||
width = 1080
|
||||
height = 1920
|
||||
|
||||
[project]
|
||||
title = SIGW-Extension
|
||||
title = SIWG-Extension
|
||||
|
||||
[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