I’m trying to use the native.reflection.callStaticMethod
But I’m getting lost. In order to call a Toast we need the main activity of the Application.
Is this the best approach ?
Is this of native calls should work right ?
if (sys.isMobile)
{
let cocosActivity = native.reflection.callStaticMethod("com/cocos/game/AppActivity", "getContext", "()Lcom/cocos/game/AppActivity;");
let toastClass = native.reflection.callStaticMethod("android/widget/Toast", "makeText", "(Landroid/content/Context;Ljava/lang/CharSequence;I)Landroid/widget/Toast;", cocosActivity, message, 0);
native.reflection.callStaticMethod("android/widget/Toast", "show", "()V", toastClass);
}
1 Like
Did you define a static method getContext in the AppActivity.java file?
zzf520
September 19, 2023, 7:05am
#3
Related documentation links: Cocos Creator 3.8 Manual - JavaScript and Android Communication with Reflection
JS Call Java
import { _decorator, Component, Label, native, Node, sys } from 'cc';
const { ccclass, property } = _decorator;
let tips_global = null;
//@ts-ignore
window.TestNativeCallJs = function () {
tips_global.string = "The test was successful...";
}
@ccclass('NativeCallCtrl')
export class NativeCallCtrl extends Component {
@property(Label)
tips: Label = null;
start() {
tips_global = this.tips;
}
onClick () {
let methodName = "showAlertDialog";
if (sys.os === sys.OS.ANDROID) {
let className = "com/cocos/game/AppActivity";
let methodSignature = "(Ljava/lang/String;Ljava/lang/String;)V";
native.reflection.callStaticMethod(className, methodName, methodSignature, "Title", "Native Call Test is OK");
}
}
}
Java Call JS
AppActivity.java:
package com.cocos.game;
import android.app.AlertDialog;
import android.content.DialogInterface;
import android.os.Bundle;
import android.content.Intent;
import android.content.res.Configuration;
import com.cocos.lib.CocosHelper;
import com.cocos.lib.CocosJavascriptJavaBridge;
import com.cocos.service.SDKWrapper;
import com.cocos.lib.CocosActivity;
public class AppActivity extends CocosActivity {
private static AppActivity app = null;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
app = this;
// DO OTHER INITIALIZATION BELOW
SDKWrapper.shared().init(this);
}
//...... Omit unmodified code here
public static void showAlertDialog(final String title, final String message) {
app.runOnUiThread(new Runnable() {
@Override
public void run() {
AlertDialog.Builder builder = new AlertDialog.Builder(app);
builder.setTitle(title);
builder.setMessage(message);
builder.setPositiveButton("OK", new DialogInterface.OnClickListener() {
@Override
public void onClick(DialogInterface dialog, int which) {
CocosHelper.runOnGameThread(new Runnable() {
@Override
public void run() {
CocosJavascriptJavaBridge.evalString("TestNativeCallJs()");
}
});
}
});
AlertDialog alertDialog = builder.create();
alertDialog.show();
}
});
}
}
This is demo:
59480.zip (863.7 KB)
The modified AppActivity.java is in:
native/engine/android/app/src/com/cocos/game
1 Like
zzf520
September 19, 2023, 8:49am
#4
Now I updated the iOS platform method:
Related documnentation links: Cocos Creator 3.8 Manual - JavaScript and iOS/macOS Communication with Reflection
JS Call OC:
onClick () {
if (sys.os === sys.OS.ANDROID) {
let className = "com/cocos/game/AppActivity";
let methodName = "showAlertDialog";
let methodSignature = "(Ljava/lang/String;Ljava/lang/String;)V";
native.reflection.callStaticMethod(className, methodName, methodSignature, "Title", "Native Call Test is OK");
} else if (sys.os === sys.OS.IOS) {
let className = "AppDelegate";
let methodName = "showAlertDialog:withMessage:";
native.reflection.callStaticMethod(className, methodName, "Title", "Native Call Test is OK");
}
}
OC Call JS:
AppDelegate.mm:
#import "AppDelegate.h"
#import "ViewController.h"
#import "View.h"
#include "platform/ios/IOSPlatform.h"
#import "platform/ios/AppDelegateBridge.h"
#import "service/SDKWrapper.h"
#import "cocos/bindings/jswrapper/SeApi.h"
@implementation AppDelegate
static ViewController* rootViewController = nullptr;
@synthesize window;
@synthesize appDelegateBridge;
#pragma mark -
#pragma mark Application lifecycle
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[[SDKWrapper shared] application:application didFinishLaunchingWithOptions:launchOptions];
appDelegateBridge = [[AppDelegateBridge alloc] init];
// Add the view controller's view to the window and display.
CGRect bounds = [[UIScreen mainScreen] bounds];
self.window = [[UIWindow alloc] initWithFrame:bounds];
// Should create view controller first, cc::Application will use it.
_viewController = [[ViewController alloc] init];
rootViewController = _viewController;
_viewController.view = [[View alloc] initWithFrame:bounds];
_viewController.view.contentScaleFactor = UIScreen.mainScreen.scale;
_viewController.view.multipleTouchEnabled = true;
[self.window setRootViewController:_viewController];
[self.window makeKeyAndVisible];
[appDelegateBridge application:application didFinishLaunchingWithOptions:launchOptions];
return YES;
}
//...... Omit unmodified code here
+ (void)showAlertDialog:(NSString *)title withMessage:(NSString *)message {
UIAlertController* alert = [UIAlertController alertControllerWithTitle:title message:message preferredStyle:UIAlertControllerStyleAlert];
UIAlertAction* defaultAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction * action) {
se::ScriptEngine::getInstance()->evalString("TestNativeCallJs()");
}];
[alert addAction:defaultAction];
[rootViewController presentViewController:alert animated:NO completion:nil];
}
//...... Omit unmodified code here
@end
This is demo:
59480_iOS.zip (1.4 MB)
The modified AppDelegate.mm in:
native/engine/ios
1 Like
Ok I get the idea. We can only make call and get this data, int, float, boolean,String.
No support for native objects.
The example was even better than what I ask.
The toast message should work, like this then.
Java
public static void showToast(String message, int length)
{
app.runOnUiThread(new Runnable() {
@Override
public void run() {
Toast.makeText(app, message, length).show();
}
});
}
TypeScript
public static showToast (message: string, length:number): void
{
if (sys.os === sys.OS.ANDROID)
{
let className = "com/cocos/game/AppActivity";
let methodName = "showToast";
let methodSignature = "(Ljava/lang/String;I)V";
native.reflection.callStaticMethod(className, methodName, methodSignature, message, length);
}
}
But I’m not sure about this I mean yes this is how works. But the AppActivity.java should be manually change every time the native folder is created?. Is there a way to override the AppActivity when generating the Android project ?
zzf520
September 20, 2023, 1:49am
#6
There is no need to re-modify AppActivity.java after each build