Currently, Lynx is not suitable for building a new application from scratch. You need to integrate Lynx (engine) with your native mobile app or web app, and load Lynx apps through Lynx views. With a few steps, you can start developing with Lynx in your application.
Choose your target platform to view the specific integration steps:
Using Cocoapods can easily integrate Lynx into your application
The core capabilities of Lynx Engine include basic capabilities such as parsing Bundle, style parsing, layout, and rendering views
Get the latest version of Lynx from Cocoapods. Then add Lynx to your Podfile:
source 'https://cdn.cocoapods.org/'
platform :ios, '10.0'
target 'YourTarget' do
pod 'Lynx', '3.2.0', :subspecs => [
'Framework',
]
pod 'PrimJS', '2.12.0', :subspecs => ['quickjs', 'napi']
end
Lynx Service includes LynxImageService
, LynxLogService
, etc. It aims to provide the ability to strongly correlate some host App features, allowing the App to inject custom Services at runtime, or use the default implementation provided by the official. For example, LynxImageService
is implemented using the SDWebImage image library by default. Apps that do not integrate SDWebImage components can rely on other image libraries to implement Image Service.
Lynx provides standard native Image, Log, and Http service capabilities, which can be quickly accessed and used by the access party;
Get the latest version of Lynx Service from Cocoapods. Then add Lynx Service to your Podfile:
source 'https://cdn.cocoapods.org/'
platform :ios, '10.0'
target 'YourTarget' do
pod 'Lynx', '3.2.0', :subspecs => [
'Framework',
]
pod 'PrimJS', '2.12.0', :subspecs => ['quickjs', 'napi']
# integrate image-service, log-service, and http-service
pod 'LynxService', '3.2.0', :subspecs => [
'Image',
'Log',
'Http',
]
# ImageService dependencies:
pod 'SDWebImage','5.15.5'
pod 'SDWebImageWebPCoder', '0.11.0'
end
XElement is a UI library maintained by the Lynx team. It provides richer component capabilities, enabling faster adoption of Lynx in production environments and enhancing the vibrancy of the Lynx ecosystem.
source 'https://cdn.cocoapods.org/'
platform :ios, '10.0'
target 'YourTarget' do
pod 'Lynx', '3.2.0', :subspecs => [
'Framework',
]
pod 'PrimJS', '2.12.0', :subspecs => ['quickjs', 'napi']
# integrate image-service, log-service, and http-service
pod 'LynxService', '3.2.0', :subspecs => [
'Image',
'Log',
'Http',
]
# ImageService
pod 'SDWebImage','5.15.5'
pod 'SDWebImageWebPCoder', '0.11.0'
pod 'XElement', '3.4.0'
end
Run pod install
to install dependencies, then open your Xcode project. Additionally, make sure to disable the Sandbox Scripting capability.
In order to disable the Sandbox scripting, in Xcode click on your app, then on build settings. Filter for script and set the User Script Sandboxing to NO.
LynxEnv provides a global initialization interface for the Lynx Engine. Please ensure that the initialization of LynxEnv occurs before any interface call of the Lynx Engine.
For example, it can be initialized in AppDelegate
#import <Lynx/LynxEnv.h>
#import <Lynx/LynxView.h>
@implementation AppDelegate
- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
[LynxEnv sharedInstance];
return YES;
}
LynxView is the basic rendering unit provided by Lynx Engine. LynxView is an implementation inherited from iOS native UIView. You can quickly construct a LynxView and add it to the ViewController.
Lynx Engine itself does not have the ability to load resources, so it is necessary to initialize LynxEnv, or when constructing LynxView to pass in the specific implementation of the LynxTemplateProvider
protocol. Lynx will use the injected resource loader to obtain the Bundle content
You can use various methods to obtain the contents of the Bundle. Here, we choose to embed the contents of the Bundle within the application.
Steps to embed files:
#import <Foundation/Foundation.h>
#import <Lynx/LynxTemplateProvider.h>
NS_ASSUME_NONNULL_BEGIN
@interface DemoLynxProvider : NSObject <LynxTemplateProvider>
@end
NS_ASSUME_NONNULL_END
#import <Foundation/Foundation.h>
#import "DemoLynxProvider.h"
@implementation DemoLynxProvider
- (void)loadTemplateWithUrl:(NSString*)url onComplete:(LynxTemplateLoadBlock)callback {
NSString *filePath = [[NSBundle mainBundle] pathForResource:url ofType:@"bundle"];
if (filePath) {
NSError *error;
NSData *data = [NSData dataWithContentsOfFile:filePath options:0 error:&error];
if (error) {
NSLog(@"Error reading file: %@", error.localizedDescription);
callback(nil, error);
} else {
callback(data, nil);
}
} else {
NSError *urlError = [NSError errorWithDomain:@"com.lynx"
code:400
userInfo:@{NSLocalizedDescriptionKey : @"Invalid URL."}];
callback(nil, urlError);
}
}
@end
you may construct a basic LynxView as follows:
#import <Lynx/LynxView.h>
#import "ViewController.h"
#import "DemoLynxProvider.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
LynxView *lynxView = [[LynxView alloc] initWithBuilderBlock:^(LynxViewBuilder *builder) {
builder.config = [[LynxConfig alloc] initWithProvider:[[DemoLynxProvider alloc] init]];
builder.screenSize = self.view.frame.size;
builder.fontScale = 1.0;
}];
lynxView.preferredLayoutWidth = self.view.frame.size.width;
lynxView.preferredLayoutHeight = self.view.frame.size.height;
lynxView.layoutWidthMode = LynxViewSizeModeExact;
lynxView.layoutHeightMode = LynxViewSizeModeExact;
}
@end
and then, adding the LynxView to the window.
#import <Lynx/LynxView.h>
#import "ViewController.h"
#import "DemoLynxProvider.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// ...
[self.view addSubview:lynxView];
}
@end
After completing the above steps, all the work of initializing LynxView have been completed. Call the lynxView.loadTemplateFromURL
method to render the corresponding Bundle onto the LynxView.
#import <Lynx/LynxView.h>
#import "ViewController.h"
#import "DemoLynxProvider.h"
@implementation ViewController
- (void)viewDidLoad {
[super viewDidLoad];
// ...
[lynxView loadTemplateFromURL:@"main.lynx" initData:nil];
}
@end
Then you will see the following interface on the screen:
Congratulations, you have now completed all the work of integrating Lynx Engine!
At this stage, you have successfully integrated Lynx into your App. Refer to our developing and debugging docs for in-depth insights on working with Lynx.
The core capabilities of Lynx Engine include basic capabilities such as parsing Bundle, style parsing, layout, rendering views and the basic code of the javascript runtime that Lynx pages rely on
dependencies {
// lynx dependencies
implementation "org.lynxsdk.lynx:lynx:3.2.0"
implementation "org.lynxsdk.lynx:lynx-jssdk:3.2.0"
implementation "org.lynxsdk.lynx:lynx-trace:3.2.0"
implementation "org.lynxsdk.lynx:primjs:2.12.0"
}
Lynx Service includes LynxImageService
, LynxLogService
, etc. It aims to provide the ability to strongly correlate some host App features, allowing the App to inject custom Services at runtime, or use the default implementation provided by the official.For example, LynxImageService
is implemented using the Fresco image library by default. Apps that do not integrate Fresco components can rely on other image libraries, such as Glide to implement Image Service.
Lynx provides standard native Image, Log, and Http service capabilities, which can be quickly accessed and used by the access party;
dependencies {
// lynx dependencies
implementation "org.lynxsdk.lynx:lynx:3.2.0"
implementation "org.lynxsdk.lynx:lynx-jssdk:3.2.0"
implementation "org.lynxsdk.lynx:lynx-trace:3.2.0"
implementation "org.lynxsdk.lynx:primjs:2.12.0"
// integrating image-service
implementation "org.lynxsdk.lynx:lynx-service-image:3.2.0"
// image-service dependencies, if not added, images cannot be loaded; if the host APP needs to use other image libraries, you can customize the image-service and remove this dependency
implementation "com.facebook.fresco:fresco:2.3.0"
implementation "com.facebook.fresco:animated-gif:2.3.0"
implementation "com.facebook.fresco:animated-webp:2.3.0"
implementation "com.facebook.fresco:webpsupport:2.3.0"
implementation "com.facebook.fresco:animated-base:2.3.0"
implementation "com.squareup.okhttp3:okhttp:4.9.0"
// integrating log-service
implementation "org.lynxsdk.lynx:lynx-service-log:3.2.0"
// integrating http-service
implementation "org.lynxsdk.lynx:lynx-service-http:3.2.0"
}
The obfuscation rules for Lynx Engine
are as follows. It is recommended to refer to the latest source code configuration.
# LYNX START
# use @Keep to annotate retained classes.
-dontwarn android.support.annotation.Keep
-keep @android.support.annotation.Keep class **
-keep @android.support.annotation.Keep class ** {
@android.support.annotation.Keep <fields>;
@android.support.annotation.Keep <methods>;
}
-dontwarn androidx.annotation.Keep
-keep @androidx.annotation.Keep class **
-keep @androidx.annotation.Keep class ** {
@androidx.annotation.Keep <fields>;
@androidx.annotation.Keep <methods>;
}
# native method call
-keepclasseswithmembers,includedescriptorclasses class * {
native <methods>;
}
-keepclasseswithmembers class * {
@com.lynx.tasm.base.CalledByNative <methods>;
}
# to customize a module, you need to keep the class name and the method annotated as LynxMethod.
-keepclasseswithmembers class * {
@com.lynx.jsbridge.LynxMethod <methods>;
}
-keepclassmembers class * {
@com.lynx.tasm.behavior.LynxProp <methods>;
@com.lynx.tasm.behavior.LynxPropGroup <methods>;
@com.lynx.tasm.behavior.LynxUIMethod <methods>;
}
-keepclassmembers class com.lynx.tasm.behavior.ui.UIGroup {
public boolean needCustomLayout();
}
# in case R8 compiler may remove mLoader in bytecode.
# as mLoader is not used in java and passed as a WeakRef in JNI.
-keepclassmembers class com.lynx.tasm.LynxTemplateRender {
private com.lynx.tasm.core.LynxResourceLoader mLoader;
}
# the automatically generated setter classes use the class names of LynxBaseUI and ShadowNode and their subclasses.
-keep class com.lynx.tasm.behavior.ui.LynxBaseUI
-keep class com.lynx.tasm.behavior.shadow.ShadowNode
-keep class com.lynx.jsbridge.LynxModule { *; }
-keep class * extends com.lynx.tasm.behavior.ui.LynxBaseUI
-keep class * extends com.lynx.tasm.behavior.shadow.ShadowNode
-keep class * extends com.lynx.jsbridge.LynxModule { *; }
-keep class * extends com.lynx.jsbridge.LynxContextModule
-keep class * implements com.lynx.tasm.behavior.utils.Settable
-keep class * implements com.lynx.tasm.behavior.utils.LynxUISetter
-keep class * implements com.lynx.tasm.behavior.utils.LynxUIMethodInvoker
-keep class com.lynx.tasm.rendernode.compat.**{
*;
}
-keep class com.lynx.tasm.rendernode.compat.RenderNodeFactory{
*;
}
# LYNX END
Application#onCreate
lifecycle of the application.Please specify your custom Application class in the AndroidManifest.xml file, since Lynx needs to perform some global initialization operations when the application starts.
<application
android:name=".YourApplication">
</application>
import android.app.Application;
import com.facebook.drawee.backends.pipeline.Fresco;
import com.facebook.imagepipeline.core.ImagePipelineConfig;
import com.facebook.imagepipeline.memory.PoolConfig;
import com.facebook.imagepipeline.memory.PoolFactory;
import com.lynx.service.http.LynxHttpService;
import com.lynx.service.image.LynxImageService;
import com.lynx.service.log.LynxLogService;
import com.lynx.tasm.service.LynxServiceCenter;
public class YourApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
initLynxService();
}
private void initLynxService() {
// init Fresco which is needed by LynxImageService
final PoolFactory factory = new PoolFactory(PoolConfig.newBuilder().build());
ImagePipelineConfig.Builder builder =
ImagePipelineConfig.newBuilder(getApplicationContext()).setPoolFactory(factory);
Fresco.initialize(getApplicationContext(), builder.build());
LynxServiceCenter.inst().registerService(LynxImageService.getInstance());
LynxServiceCenter.inst().registerService(LynxLogService.INSTANCE);
LynxServiceCenter.inst().registerService(LynxHttpService.INSTANCE);
}
}
LynxEnv provides the global initialization interface for the Lynx Engine. Please ensure that the initialization of LynxEnv occurs before any interface calls to the Lynx Engine. It is recommended to complete the initialization of LynxEnv during the Application#onCreate lifecycle of the application.
import com.lynx.tasm.LynxEnv;
public class YourApplication extends Application {
@Override
public void onCreate() {
super.onCreate();
initLynxService();
initLynxEnv();
}
private void initLynxEnv() {
LynxEnv.inst().init(
this,
null,
null,
null
);
}
}
The parameters for the LynxEnv initialization method are described as follows:
Lynx Engine itself does not have the ability to integrate downloading resources, so the existing app needs to provide the specific implementation of AbsTemplateProvider
, and inject it when initializing LynxEnv or constructing LynxView. Lynx will use the injected resource loader to obtain the Bundle content
You can use various methods to obtain the contents of the Bundle. Here, we choose to embed the contents of the Bundle within the application.
app
└── src
└── main
├── java
├── res
└── assets
└── main.lynx.bundle
import android.content.Context;
import com.lynx.tasm.provider.AbsTemplateProvider;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.io.InputStream;
public class DemoTemplateProvider extends AbsTemplateProvider {
private Context mContext;
DemoTemplateProvider(Context context) {
this.mContext = context.getApplicationContext();
}
@Override
public void loadTemplate(String uri, Callback callback) {
new Thread(new Runnable() {
@Override
public void run() {
try (InputStream inputStream = mContext.getAssets().open(uri);
ByteArrayOutputStream byteArrayOutputStream = new ByteArrayOutputStream()) {
byte[] buffer = new byte[1024];
int length;
while ((length = inputStream.read(buffer)) != -1) {
byteArrayOutputStream.write(buffer, 0, length);
}
callback.onSuccess(byteArrayOutputStream.toByteArray());
} catch (IOException e) {
callback.onFailed(e.getMessage());
}
}
}).start();
}
}
LynxView
is the basic rendering view provided by Lynx Engine
. LynxView
inherits from the native Android View. You can quickly construct a LynxView and add it arbitrarily to the native Android view tree.
import android.app.Activity;
import android.os.Bundle;
import com.lynx.tasm.LynxView;
import com.lynx.tasm.LynxViewBuilder;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LynxView lynxView = buildLynxView();
setContentView(lynxView);
}
private LynxView buildLynxView() {
LynxViewBuilder viewBuilder = new LynxViewBuilder();
viewBuilder.setTemplateProvider(new DemoTemplateProvider(this));
return viewBuilder.build(this);
}
}
XElement is a UI library maintained by the Lynx team. It provides richer component capabilities, enabling faster adoption of Lynx in production environments and enhancing the vibrancy of the Lynx ecosystem.
dependencies {
// lynx dependencies
implementation "org.lynxsdk.lynx:lynx:3.2.0"
implementation "org.lynxsdk.lynx:lynx-jssdk:3.2.0"
implementation "org.lynxsdk.lynx:lynx-trace:3.2.0"
implementation "org.lynxsdk.lynx:primjs:2.12.0"
// integrating image-service
implementation "org.lynxsdk.lynx:lynx-service-image:3.2.0"
// image-service dependencies, if not added, images cannot be loaded; if the host APP needs to use other image libraries, you can customize the image-service and remove this dependency
implementation "com.facebook.fresco:fresco:2.3.0"
implementation "com.facebook.fresco:animated-gif:2.3.0"
implementation "com.facebook.fresco:animated-webp:2.3.0"
implementation "com.facebook.fresco:webpsupport:2.3.0"
implementation "com.facebook.fresco:animated-base:2.3.0"
implementation "com.squareup.okhttp3:okhttp:4.9.0"
// integrating log-service
implementation "org.lynxsdk.lynx:lynx-service-log:3.2.0"
// integrating http-service
implementation "org.lynxsdk.lynx:lynx-service-http:3.2.0"
// integrating XElement
implementation "org.lynxsdk.lynx:xelement:3.4.0"
implementation "org.lynxsdk.lynx:xelement:3.4.0"
}
XElement requires additional importation in the LynxViewBuilder
:
import android.app.Activity;
import android.os.Bundle;
import com.lynx.tasm.LynxView;
import com.lynx.tasm.LynxViewBuilder;
import com.lynx.xelement.XElementBehaviors;
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LynxView lynxView = buildLynxView();
setContentView(lynxView);
}
private LynxView buildLynxView() {
LynxViewBuilder viewBuilder = new LynxViewBuilder();
viewBuilder.addBehaviors(new XElementBehaviors().create());
viewBuilder.setTemplateProvider(new DemoTemplateProvider(this));
return viewBuilder.build(this);
}
}
After completing the above steps, all the work of initializing LynxView have been completed. Call the lynxView.renderTemplateUrl
method to render the corresponding Bundle onto the LynxView view.
public class MainActivity extends Activity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
LynxView lynxView = buildLynxView();
setContentView(lynxView);
String url = "main.lynx.bundle";
lynxView.renderTemplateUrl(url, "");
}
}
Then you will see the following interface on the screen:
Congratulations, you have now completed all the work of rendering the LynxView!
At this stage, you have successfully integrated Lynx into your App. Refer to our developing and debugging docs for in-depth insights on working with Lynx.
The core capabilities of the Lynx Engine, including parsing the Bundle, style parsing, layout, rendering views, and the basic JavaScript runtime code that Lynx pages depend on.
Lynx Service, which includes LynxDevtoolService
, LynxLogService
, and more, is designed to provide capabilities closely related to host application features, allowing the host application to inject custom implementations at runtime, or use the default implementations provided by Lynx. For example, LynxHttpService uses the built-in HTTP module of HarmonyOS by default. Lynx provides standard native Log and HTTP service capabilities, allowing integrators to quickly integrate and use them;
"dependencies": {
"@ohos/imageknife": "3.2.6",
"@lynx/lynx": "3.4.0",
"@lynx/lynx_devtool": "3.4.0",
"@lynx/lynx_devtool_service": "3.4.0",
"@lynx/lynx_http_service": "3.4.0",
"@lynx/lynx_log_service": "3.4.0",
"@lynx/primjs": "2.14.0",
},
To import libc++_shared.so
, you need to configure Native C++. This requires defining a CMakeLists.txt
file.
# the minimum version of CMake.
cmake_minimum_required(VERSION 3.5.0)
project(MyApplication)
And modify the buildOptions
in entry/build-profile.json5
:
{
"buildOption": {
"externalNativeOptions": {
"path": "./src/main/cpp/CMakeLists.txt",
"arguments": "",
"cppFlags": "",
}
},
}
If you need to request network resources, configure requestPermissions
in module.json5
to enable network requests.
{
"module": {
"requestPermissions": [
{
"name": "ohos.permission.INTERNET",
"reason": "$string:network",
"usedScene": {
"abilities": [
"FormAbility"
],
"when": "inuse"
}
},
],
}
}
And configure the network
key field in entry/src/main/resources/base/element/string.json
:
{
"string": [
{
"name": "network",
"value": "Request network"
}
]
}
Lynx Service
provides capabilities related to host features. It is recommended to complete the Lynx Service
initialization in the OnCreate
lifecycle of EntryAbility
.
import { LLog, LynxServiceCenter, LynxEnv, LynxServiceType } from '@lynx/lynx';
import { LynxDevToolService } from '@lynx/lynx_devtool_service';
import { LynxLogService } from '@lynx/lynx_log_service';
import { LynxHttpService } from '@lynx/lynx_http_service';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// Init LynxDevtoolService
LynxServiceCenter.registerService(LynxServiceType.DevTool, LynxDevToolService.instance);
// Init LynxHttpService
LynxServiceCenter.registerService(LynxServiceType.Http, LynxHttpService.instance);
// Init LynxLogService
LynxServiceCenter.registerService(LynxServiceType.Log, LynxLogService.instance);
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
}
}
LynxEnv
provides the global initialization interface for the Lynx Engine
. Please ensure that LynxEnv
is initialized before any other Lynx Engine
interfaces are called. For example, this can be done in the OnCreate
lifecycle of EntryAbility
.
import { LLog, LynxEnv } from '@lynx/lynx';
export default class EntryAbility extends UIAbility {
onCreate(want: Want, launchParam: AbilityConstant.LaunchParam): void {
// Init LynxService
// ...
// Init LynxEnv
LLog.useSysLog(true);
LynxEnv.initialize(this.context);
let options = new Map<string, string>();
options.set('App', 'LynxExplorer');
options.set('AppVersion', '0.0.1');
LynxEnv.setAppInfo(options);
LynxEnv.enableDevtool(true);
hilog.info(DOMAIN, 'testTag', '%{public}s', 'Ability onCreate');
}
}
The Lynx Engine
itself does not have a built-in capability for downloading resources. Therefore, the host application must provide a specific implementation of LynxResourceProvider
and inject it when constructing a LynxView
. Lynx will then use the injected resource loader to fetch the actual Bundle content.
You can obtain the Bundle's resource content in various ways. Here, we'll choose to embed the Bundle's content directly within the application:
First, place the Bundle file generated during the quick start phase into the src/main/resources/rawfile
directory. Alternatively, you can download the following file and place it in the same directory:
entry
└── src
└── main
└── resources
└── rawfile
└── main.lynx.bundle
LynxTemplateResourceFetcher
provides the capability to load Bundle template resources. You need to implement the fetchTemplate
method to handle the loading.
import { LLog, LynxResourceRequest, LynxTemplateResourceFetcher, TemplateProviderResult } from '@lynx/lynx';
import { AsyncCallback, BusinessError } from '@ohos.base';
import http from '@ohos.net.http';
import resourceManager from '@ohos.resourceManager';
export class ExampleTemplateResourceFetcher extends LynxTemplateResourceFetcher {
fetchTemplate(request: LynxResourceRequest,
callback: AsyncCallback<TemplateProviderResult, void>) {
if (request.url.startsWith('http')) {
let httpRequest = http.createHttp();
httpRequest.request(
request.url, {
expectDataType: http.HttpDataType.ARRAY_BUFFER,
}, (err: BusinessError, data: http.HttpResponse) => {
callback(err, {
binary: data?.result as ArrayBuffer
});
httpRequest.destroy();
});
} else {
// local file
const context: Context = getContext(this);
const resourceMgr: resourceManager.ResourceManager = context.resourceManager;
resourceMgr.getRawFileContent(request.url, (err: BusinessError, data: Uint8Array) => {
callback(err, {
binary: data?.buffer as ArrayBuffer
})
});
}
}
fetchSSRData(request: LynxResourceRequest, callback: AsyncCallback<ArrayBuffer, void>) {
let httpRequest = http.createHttp();
httpRequest.request(request.url, {
expectDataType: http.HttpDataType.ARRAY_BUFFER
}, (err: BusinessError, data: http.HttpResponse) => {
callback(err, data?.result as ArrayBuffer)
httpRequest.destroy();
})
}
}
LynxMediaResourceFetcher
provides the capability to load media resources.
import { LynxMediaResourceFetcher, LynxResourceRequest, LynxOptionalBool } from '@lynx/lynx';
export class ExampleMediaResourceFetcher extends LynxMediaResourceFetcher {
shouldRedirectUrl(request: LynxResourceRequest): string {
// just return the input url;
return request.url;
}
isLocalResource(url: string): LynxOptionalBool {
return LynxOptionalBool.UNDEFINED;
}
}
LynxGenericResourceFetcher
provides the capability to load generic resources. You need to implement the fetchResource
method to handle the loading.
import { LynxError, LynxSubErrorCode, LynxGenericResourceFetcher, LynxResourceRequest, LynxResourceType, LynxStreamDelegate } from '@lynx/lynx';
import { AsyncCallback, BusinessError } from '@ohos.base';
import http from '@ohos.net.http';
import { ImageKnife, ImageKnifeOption, CacheStrategy } from '@ohos/imageknife';
export class ExampleGenericResourceFetcher extends LynxGenericResourceFetcher {
fetchResource(request: LynxResourceRequest, callback: AsyncCallback<ArrayBuffer, void>): void {
let httpRequest = http.createHttp();
httpRequest.request(request.url, {
expectDataType: http.HttpDataType.ARRAY_BUFFER
}, (err: BusinessError, data: http.HttpResponse) => {
callback(err, data?.result as ArrayBuffer)
httpRequest.destroy();
})
}
fetchResourcePath(request: LynxResourceRequest, callback: AsyncCallback<string, void>): void {
if (request.type === LynxResourceType.LYNX_RESOURCE_TYPE_IMAGE) {
let option = new ImageKnifeOption();
option.loadSrc = request.url;
option.writeCacheStrategy = CacheStrategy.File;
let error: BusinessError | undefined = undefined;
ImageKnife.getInstance().preLoadCache(option).then((data: string) => {
if (data.length > 0) {
callback(error, data);
} else {
error = {
code: LynxSubErrorCode.E_RESOURCE_IMAGE_PIC_SOURCE,
message: 'Image path is invalid',
name: 'Image Error',
}
callback(error, '');
}
}).catch((e: string) => {
error = {
code: LynxSubErrorCode.E_RESOURCE_IMAGE_FROM_NETWORK_OR_OTHERS,
message: e,
name: 'Image Error',
}
callback(error, '');
})
} else {
callback({
code: LynxError.LYNX_ERROR_CODE_RESOURCE,
message: 'unsupported type: ' + request.type,
name: 'Resource Error',
}, '');
}
}
fetchStream(request: LynxResourceRequest, delegate: LynxStreamDelegate): void {
// TODO(Lynx): support fetching stream.
delegate.onStart(100);
let a = new ArrayBuffer(10);
delegate.onData(a, 0, 10);
delegate.onEnd();
}
cancel(request: LynxResourceRequest): void {
// TODO(Lynx)
}
}
Once you have completed the steps above, you have finished all the necessary work for creating the LynxView
and reading its resources. You can now render the corresponding Bundle content onto the LynxView
.
import {
LynxTemplateResourceFetcher,
LynxMediaResourceFetcher,
LynxGenericResourceFetcher,
LynxView,
} from '@lynx/lynx';
import { ExampleTemplateResourceFetcher } from '../provider/ExampleTemplateResourceFetcher';
import { ExampleMediaResourceFetcher } from '../provider/ExampleMediaResourceFetcher';
import { ExampleGenericResourceFetcher } from '../provider/ExampleGenericResourceFetcher';
@Entry
@Component
struct Index {
templateResourceFetcher: LynxTemplateResourceFetcher = new ExampleTemplateResourceFetcher();
mediaResourceFetcher: LynxMediaResourceFetcher = new ExampleMediaResourceFetcher();
genericResourceFetcher: LynxGenericResourceFetcher = new ExampleGenericResourceFetcher();
private url: string = 'your bundle file';
build() {
Column() {
LynxView({
templateResourceFetcher: this.templateResourceFetcher,
mediaResourceFetcher: this.mediaResourceFetcher,
genericResourceFetcher: this.genericResourceFetcher,
url: this.url,
}).width('100%').height('100%');
}
.size({ width: '100%', height: '100%' })
}
}
You will then see the following content on your screen:
Congratulations! You have now completed the full integration of the Lynx Engine.
Now that you have integrated Lynx into your application, please refer to the Development and Debugging documentation to further explore the world of Lynx!
Lynx for Web implements the Lynx engine in web browsers. With Lynx for Web, you can easily integrate Lynx apps into any existing web project, regardless of whether the project uses React, Vue, Svelte, or plain HTML.
We need you to have read and created a Lynx project according to Quick Start.
cd <lynx-project-name>
environments.web
) to lynx.config.ts
:import { defineConfig } from '@lynx-js/rspeedy';
import { pluginReactLynx } from '@lynx-js/react-rsbuild-plugin';
export default defineConfig({
plugins: [pluginReactLynx()],
environments: {
web: {
output: {
assetPrefix: '/',
},
},
lynx: {},
},
});
Run:
npm run build
You will see an additional dist/main.web.bundle
file in this project, which is the final web build artifact.
Now that you have a Lynx for Web build artifact, we need to create a web project to use it. Here we use Rsbuild.
Create a new project at the same level as the Lynx project above and run:
npm create rsbuild@latest
Follow the prompts to create a React project.
cd <web-project-name>
npm install @lynx-js/web-core @lynx-js/web-elements
src/app.tsx
import './App.css';
import '@lynx-js/web-core/index.css';
import '@lynx-js/web-elements/index.css';
import '@lynx-js/web-core';
import '@lynx-js/web-elements/all';
const App = () => {
return (
<lynx-view
style={{ height: '100vh', width: '100vw' }}
url="/main.web.bundle"
></lynx-view>
);
};
export default App;
rsbuild.config.ts
server.publicDir
needs to be replaced with your actual Lynx project path.
import { defineConfig } from '@rsbuild/core';
import { pluginReact } from '@rsbuild/plugin-react';
import path from 'node:path';
import { fileURLToPath } from 'node:url';
const __filename = fileURLToPath(import.meta.url);
const __dirname = path.dirname(__filename);
export default defineConfig({
plugins: [pluginReact()],
server: {
publicDir: [
{
name: path.join(
__dirname,
'../',
// Please replace this with your actual Lynx project name
'lynx-project',
'dist',
),
},
],
},
});
Run:
npm run dev
Visit http://localhost:3000
to see your Lynx application.