Lynx

LynxInspectorConsoleDelegate

A protocol (or interface) used to receive all console messages from a LynxView instance.

Info

Currently, it only supports getting BTS console messages when using the PrimJS engine.

Syntax

Implement LynxInspectorConsoleDelegate protocol (or interface) and receive console messages through the onConsoleMessage method.

iOS

LynxInspectorConsoleDelegate.h
@protocol LynxInspectorConsoleDelegate <NSObject>

- (void)onConsoleMessage:(NSString *)msg;

@end

Android

LynxInspectorConsoleDelegate.java
public interface LynxInspectorConsoleDelegate {
  void onConsoleMessage(String msg);
}

Harmony

LynxInspectorConsoleDelegate.ets
export interface LynxInspectorConsoleDelegate {
  onConsoleMessage: (msg: string) => void;
}

Data Format

All data is in the form of a JSON formatted string.

For Object type data, only the basic information of the Object is included. You can use getConsoleObject to get more detailed data.

onConsoleMessage

FieldTypeDescription
typestringThe log type, such as log, debug, info, error, warning, etc.
argsarray[argument]The log arguments, an array where each element is an argument object.

argument

FieldTypeDescription
typestringThe argument type, such as string, number, boolean, object, function, undefined, etc.
subtypestringOptional field, the subtype of the argument, such as array, null, error, etc. This is specified only for arguments of type object.
objectIdstringOptional field, the unique identifier when the argument is an Object type.
descriptionstringOptional field, a preview or description of the argument.
valueanyOptional field, the value of the argument.

Example

let testObj = { a: 1, b: 'test', c: true, d: undefined, e: null, f: { g: 2 } };
console.log('test object: ', testObj);

The code above will trigger the onConsoleMessage event, and the event data is as follows:

"{\"type\":\"log\",\"args\":[{\"value\":\"test object: \",\"type\":\"string\"},{\"type\":\"object\",\"objectId\":\"546729222512\",\"className\":\"Object\",\"description\":\"Object\"}]}"

Take the objectId field from the second argument and call the getConsoleObject method.

When needStringify is false, the returned data is as follows:

"[{\"name\":\"a\",\"value\":{\"description\":\"1\",\"value\":1,\"type\":\"number\"}},{\"name\":\"b\",\"value\":{\"value\":\"test\",\"type\":\"string\"}},{\"name\":\"c\",\"value\":{\"value\":true,\"type\":\"boolean\"}},{\"name\":\"d\",\"value\":{\"type\":\"undefined\"}},{\"name\":\"e\",\"value\":{\"subtype\":\"null\",\"value\":null,\"type\":\"object\"}},{\"name\":\"f\",\"value\":{\"type\":\"object\",\"objectId\":\"546729222592\",\"className\":\"Object\",\"description\":\"Object\"}},{\"name\":\"__proto__\",\"value\":{\"type\":\"object\",\"objectId\":\"546824040688\",\"className\":\"Object\",\"description\":\"Object\"}}]"

When needStringify is true, the returned data is as follows:

"{\n\t\"a\": 1,\n\t\"b\": \"test\",\n\t\"c\": true,\n\t\"e\": null,\n\t\"f\": {\n\t\t\"g\": 2\n\t}\n}"

Usage Example

Implementation Steps

  1. Implement LynxInspectorConsoleDelegate.
  2. Get the LynxBaseInspectorOwner instance.
  3. Register LynxInspectorConsoleDelegate.
  4. Get detailed Object information.

Code Example

iOS

TestConsoleDelegate.h
#import <Foundation/Foundation.h>
#import <Lynx/LynxBaseInspectorOwner.h>
#import <Lynx/LynxInspectorConsoleDelegate.h>

@interface TestConsoleDelegate : NSObject <LynxInspectorConsoleDelegate>

- (instancetype)initWithInspectorOwner:(id<LynxBaseInspectorOwner>)owner;

@end
TestConsoleDelegate.m
#import "TestConsoleDelegate.h"

@implementation TestConsoleDelegate {
  __weak id<LynxBaseInspectorOwner> _owner;
}

- (instancetype)initWithInspectorOwner:(id<LynxBaseInspectorOwner>)owner {
  self = [super init];
  if (self) {
    _owner = owner;
  }
  return self;
}

- (void)onConsoleMessage:(NSString *)msg {
  NSLog(@"onConsoleMessage: %@", msg);
  NSData *data = [msg dataUsingEncoding:NSUTF8StringEncoding];
  NSDictionary *dic = [NSJSONSerialization JSONObjectWithData:data options:0 error:nil];
  for (NSDictionary *item in [dic objectForKey:@"args"]) {
    if ([item objectForKey:@"type"] && [[item objectForKey:@"type"] isEqualToString:@"object"]) {
      NSString *objectId = [item objectForKey:@"objectId"];
      id<LynxBaseInspectorOwner> strongOwner = _owner;
      if (!strongOwner) {
        break;
      }
      [strongOwner getConsoleObject:objectId
                      needStringify:NO
                      resultHandler:^(NSString *detail) {
                        NSLog(@"getConsoleObject: %@", detail);
                      }];
      [strongOwner getConsoleObject:objectId
                      needStringify:YES
                      resultHandler:^(NSString *detail) {
                        NSLog(@"getConsoleObject: %@", detail);
                      }];
    }
  }
}

@end
ViewController.m
#import <Lynx/LynxView.h>
#import <Lynx/LynxBaseInspectorOwner.h>

#import "TestConsoleDelegate.h"

@implementation ViewController

- (void)viewDidLoad {
  [super viewDidLoad];

  // ...

  id<LynxBaseInspectorOwner> owner = lynxView.baseInspectorOwner;
  TestConsoleDelegate* delegate =
      [[TestConsoleDelegate alloc] initWithInspectorOwner:owner];
  [owner setLynxInspectorConsoleDelegate:delegate];
}

@end

Android

TestConsoleDelegate.java
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import com.lynx.devtool.LynxInspectorConsoleDelegate;
import com.lynx.devtoolwrapper.LynxBaseInspectorOwner;
import com.lynx.react.bridge.Callback;
import java.lang.ref.WeakReference;
import org.json.JSONArray;
import org.json.JSONException;
import org.json.JSONObject;

public class TestConsoleDelegate implements LynxInspectorConsoleDelegate {
  private final WeakReference<LynxBaseInspectorOwner> mOwner;

  public TestConsoleDelegate(LynxBaseInspectorOwner owner) {
    mOwner = new WeakReference<>(owner);
  }

  @Override
  public void onConsoleMessage(String msg) {
    LynxBaseInspectorOwner owner = mOwner.get();
    if (owner == null) {
      return;
    }
    try {
      Log.i("TestConsoleDelegate", "onConsoleMessage: " + msg);
      JSONObject jsonObject = new JSONObject(msg);
      JSONArray args = jsonObject.getJSONArray("args");
      for (int i = 0; i < args.length(); i++) {
        JSONObject obj = new JSONObject(args.get(i).toString());
        if (obj.get("type").toString().equals("object")) {
          String objectId = obj.get("objectId").toString();
          Handler mainHandler = new Handler(Looper.getMainLooper());
          // Post task instead of calling `getConsoleObject` directly to avoid deadlock.
          mainHandler.post(new Runnable() {
            @Override
            public void run() {
              LynxBaseInspectorOwner strongOwner = mOwner.get();
              if (strongOwner == null) {
                return;
              }
              strongOwner.getConsoleObject(
                  objectId, false, new Callback() {
                    @Override
                    public void invoke(Object... args) {
                      Log.i("TestConsoleDelegate", "getConsoleObject: " + args[0].toString());
                    }
                  });
              strongOwner.getConsoleObject(
                  objectId, true, new Callback() {
                    @Override
                    public void invoke(Object... args) {
                      Log.i("TestConsoleDelegate", "getConsoleObject: " + args[0].toString());
                    }
                  });
            }
          });
        }
      }
    } catch (JSONException e) {
      // ...
    }
  }
}
MainActivity.java
import com.lynx.devtoolwrapper.LynxBaseInspectorOwner;

public class MainActivity extends Activity {

  @Override
  protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    // ...

    handleConsoleMessage(lynxView);
  }

  private void handleConsoleMessage(LynxView lynxView) {
    LynxBaseInspectorOwner owner = lynxView.getBaseInspectorOwner();
    if (owner == null) {
      return;
    }
    TestConsoleDelegate delegate = new TestConsoleDelegate(owner);
    owner.setLynxInspectorConsoleDelegate(delegate);
  }
}

Harmony

TestConsoleDelegate.ets
import {
  LynxBaseInspectorOwner,
  LynxInspectorConsoleDelegate,
} from '@lynx/lynx';

export class TestConsoleDelegate implements LynxInspectorConsoleDelegate {
  private owner: WeakRef<LynxBaseInspectorOwner>;

  constructor(owner: LynxBaseInspectorOwner) {
    this.owner = new WeakRef(owner);
  }

  public onConsoleMessage(msg: string): void {
    console.log('onConsoleMessage:', msg);
    let json: object = JSON.parse(msg);
    let args: Array<object> = json['args'];
    args.forEach((value) => {
      if (value['type'] === 'object') {
        let objectId: string = value['objectId'];
        let owner = this.owner.deref();
        if (owner) {
          owner.getConsoleObject(objectId, true, (detail: string) => {
            console.log('getConsoleObject:', detail);
          });
          owner.getConsoleObject(objectId, false, (detail: string) => {
            console.log('getConsoleObject:', detail);
          });
        }
      }
    });
  }
}
Index.ets
import { LynxView, LynxContext } from '@lynx/lynx';
import { TestConsoleDelegate } from './TestConsoleDelegate';

@Entry
@Component
struct Index {
  // ...

  build() {
    Column() {
      LynxView({
        // ...
        onCreate: (context: LynxContext) => {
          let owner = context?.getBaseInspectorOwner();
          if (owner) {
            let delegate = new TestConsoleDelegate(owner);
            owner.setLynxInspectorConsoleDelegate(delegate);
          }
        }
      }).width('100%').height('100%');
    }
  }
}

Compatibility

LCD tables only load in the browser

Except as otherwise noted, this work is licensed under a Creative Commons Attribution 4.0 International License, and code samples are licensed under the Apache License 2.0.