Skip to content

rhino module #27

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Jan 20, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion app/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ android {
}

dependencies {
implementation(project(":js"))

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.lifecycle.runtime.ktx)
Expand All @@ -96,7 +97,6 @@ dependencies {
implementation(libs.coil.video)
implementation(libs.ksoup.lite)
implementation(libs.accompanist.permissions)
implementation(libs.rhino)
implementation(libs.androidx.javascriptengine)
implementation(libs.androidx.concurrent.futures.ktx)
implementation(libs.jsoup)
Expand Down
2 changes: 2 additions & 0 deletions app/src/main/java/com/paulcoding/hviewer/MainApp.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ import android.app.Application
import android.content.Context
import com.paulcoding.hviewer.helper.CrashHandler
import com.paulcoding.hviewer.helper.setupPaths
import com.paulcoding.js.JS
import com.tencent.mmkv.MMKV

class MainApp : Application() {
Expand All @@ -12,6 +13,7 @@ class MainApp : Application() {
super.onCreate()
appContext = this
MMKV.initialize(this)
JS.initialize(this)

setupPaths()
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,10 @@ package com.paulcoding.hviewer.ui.page.post
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.paulcoding.hviewer.js.JS
import com.paulcoding.hviewer.helper.SCRIPTS_DIR
import com.paulcoding.hviewer.model.PostData
import com.paulcoding.hviewer.model.SiteConfig
import com.paulcoding.js.JS
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
Expand All @@ -15,7 +16,10 @@ class PostViewModel(private val postUrl: String, siteConfig: SiteConfig) : ViewM
private var _stateFlow = MutableStateFlow(UiState())
val stateFlow = _stateFlow.asStateFlow()

private val js = JS(siteConfig)
private val js = JS(
fileRelativePath = SCRIPTS_DIR + "/${siteConfig.scriptFile}",
properties = mapOf("baseUrl" to siteConfig.baseUrl)
)

data class UiState(
val images: List<String> = listOf(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,12 @@ package com.paulcoding.hviewer.ui.page.posts
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.paulcoding.hviewer.js.JS
import com.paulcoding.hviewer.helper.SCRIPTS_DIR
import com.paulcoding.hviewer.model.PostItem
import com.paulcoding.hviewer.model.Posts
import com.paulcoding.hviewer.model.SiteConfig
import com.paulcoding.hviewer.model.Tag
import com.paulcoding.js.JS
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
Expand All @@ -18,7 +19,10 @@ class PostsViewModel(siteConfig: SiteConfig, tag: Tag) : ViewModel() {
private var _stateFlow = MutableStateFlow(UiState())
val stateFlow = _stateFlow.asStateFlow()

private val js = JS(siteConfig)
private val js = JS(
fileRelativePath = SCRIPTS_DIR + "/${siteConfig.scriptFile}",
properties = mapOf("baseUrl" to siteConfig.baseUrl)
)

data class UiState(
val postItems: List<PostItem> = listOf(),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ package com.paulcoding.hviewer.ui.page.search
import androidx.lifecycle.ViewModel
import androidx.lifecycle.ViewModelProvider
import androidx.lifecycle.viewModelScope
import com.paulcoding.hviewer.js.JS
import com.paulcoding.hviewer.helper.SCRIPTS_DIR
import com.paulcoding.hviewer.model.PostItem
import com.paulcoding.hviewer.model.Posts
import com.paulcoding.hviewer.model.SiteConfig
import com.paulcoding.js.JS
import kotlinx.coroutines.flow.MutableStateFlow
import kotlinx.coroutines.flow.asStateFlow
import kotlinx.coroutines.flow.update
Expand All @@ -16,7 +17,10 @@ class SearchViewModel(siteConfig: SiteConfig) : ViewModel() {
private var _stateFlow = MutableStateFlow(UiState())
val stateFlow = _stateFlow.asStateFlow()

private val js = JS(siteConfig)
private val js = JS(
fileRelativePath = SCRIPTS_DIR + "/${siteConfig.scriptFile}",
properties = mapOf("baseUrl" to siteConfig.baseUrl)
)

data class UiState(
val postItems: List<PostItem> = listOf(),
Expand Down
1 change: 1 addition & 0 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -4,4 +4,5 @@ plugins {
alias(libs.plugins.kotlin.android) apply false
alias(libs.plugins.kotlin.compose) apply false
id("com.google.devtools.ksp") version "2.0.21-1.0.27" apply false
alias(libs.plugins.android.library) apply false
}
5 changes: 5 additions & 0 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,8 @@ roomRuntime = "2.6.1"
webkit = "1.13.0-alpha02"
zoomable = "0.14.0"
material3 = "1.3.1"
appcompat = "1.7.0"
material = "1.12.0"

[libraries]
accompanist-permissions = { module = "com.google.accompanist:accompanist-permissions", version.ref = "accompanistPermissions" }
Expand Down Expand Up @@ -80,9 +82,12 @@ lottie-compose = { module = "com.airbnb.android:lottie-compose", version.ref = "
mmkv = { module = "com.tencent:mmkv", version.ref = "mmkv" }
rhino = { module = "org.mozilla:rhino", version.ref = "rhino" }
zoomable = { module = "me.saket.telephoto:zoomable", version.ref = "zoomable" }
androidx-appcompat = { group = "androidx.appcompat", name = "appcompat", version.ref = "appcompat" }
material = { group = "com.google.android.material", name = "material", version.ref = "material" }

[plugins]
android-application = { id = "com.android.application", version.ref = "agp" }
kotlin-android = { id = "org.jetbrains.kotlin.android", version.ref = "kotlin" }
kotlin-compose = { id = "org.jetbrains.kotlin.plugin.compose", version.ref = "kotlin" }
android-library = { id = "com.android.library", version.ref = "agp" }

4 changes: 4 additions & 0 deletions jitpack.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
jdk:
- openjdk17
install:
- ./gradlew :js:publishReleasePublicationToMavenLocal
1 change: 1 addition & 0 deletions js/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
/build
142 changes: 142 additions & 0 deletions js/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,142 @@
# Android JavaScript Library

A Kotlin-based Android library that provides seamless JavaScript execution and integration capabilities using Mozilla's Rhino engine.

## Features

- Execute JavaScript code from strings or files
- Built-in functions for network requests (fetch, xhr)
- Base64 encoding/decoding support
- Console logging
- File importing capability
- JSON conversion utilities
- Coroutine support for asynchronous operations

## Installation

Add the following dependency to your app's `build.gradle.kts`:

```kotlin
dependencies {
implementation("com.paulcoding:js:1.0.0") // Replace with actual version
}
```

## Initialization

Initialize the library in your Application class:

```kotlin
class MyApplication : Application() {
override fun onCreate() {
super.onCreate()
JS.initialize(applicationContext)
}
}
```

## Usage

### Basic JavaScript Execution

```kotlin
// Create JS instance
val js = JS()

// Execute JavaScript string
suspend fun executeJs() {
js.evaluateString<String>("'Hello, World!'")
.onSuccess { result ->
println(result) // Prints: Hello, World!
}
.onFailure { error ->
error.printStackTrace()
}
}

// Call JavaScript function
suspend fun callJsFunction() {
js.callFunction<Int>("add", arrayOf(2, 3))
.onSuccess { result ->
println(result) // Prints: 5
}
}
```

### Loading JavaScript from File

```kotlin
// Load from file in app's files directory
val js = JS("scripts", "main.js")

// Or with full path
val js = JS(File("/path/to/script.js"))
```

### Built-in Functions

The library provides several built-in JavaScript functions:

#### fetch()
```javascript
const html = fetch('https://example.com')
```

#### xhr()
```javascript
const data = xhr('https://api.example.com/data')
```

#### import()
```javascript
import('utils.js')
```

#### console.log()
```javascript
console.log('Debug message')
```

#### atob()
```javascript
const decoded = atob('SGVsbG8gV29ybGQ=')
```

### Custom Properties

You can pass custom properties to the JavaScript environment:

```kotlin
val properties = mapOf(
"apiKey" to "your-api-key",
"baseUrl" to "https://api.example.com"
)
val js = JS(properties = properties)
```

## Dependencies

- [Rhino](https://github.com/mozilla/rhino): JavaScript engine
- [Ktor](https://ktor.io/): HTTP client
- [Gson](https://github.com/google/gson): JSON parsing
- [JSoup](https://jsoup.org/): HTML parsing

## Proguard

```
-keepattributes Signature
-dontwarn org.mozilla.javascript.**
-keep class org.mozilla.javascript.** { *; }
-keep class org.jsoup.** { *; }
-dontwarn org.jspecify.annotations.NullMarked
```

## Requirements

- Minimum SDK: 24
- Kotlin: 1.8+
- Java: 11

## License

[License](LICIENSE)
92 changes: 92 additions & 0 deletions js/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,92 @@
plugins {
alias(libs.plugins.android.library)
alias(libs.plugins.kotlin.android)
`maven-publish`
}

android {
namespace = "com.paulcoding.js"
compileSdk = 34

defaultConfig {
minSdk = 24

testInstrumentationRunner = "androidx.test.runner.AndroidJUnitRunner"
consumerProguardFiles("consumer-rules.pro")
}

buildTypes {
release {
isMinifyEnabled = false
proguardFiles(
getDefaultProguardFile("proguard-android-optimize.txt"),
"proguard-rules.pro"
)
}
}
compileOptions {
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
}
kotlinOptions {
jvmTarget = "11"
}
buildFeatures {
buildConfig = true
}
}

dependencies {

implementation(libs.androidx.core.ktx)
implementation(libs.androidx.appcompat)
implementation(libs.material)

implementation(libs.rhino)
implementation(libs.jsoup)
implementation(libs.gson)
implementation(libs.ktor.client.core)
implementation(libs.ktor.client.android)
implementation(libs.ktor.client.content.negotiation)
implementation(libs.ktor.client.logging)
implementation(libs.ktor.serialization.gson)

testImplementation(libs.junit)
androidTestImplementation(libs.androidx.junit)
androidTestImplementation(libs.androidx.espresso.core)
}

afterEvaluate {
publishing {
publications {
create<MavenPublication>("release") {
from(components["release"])

groupId = "com.github.paulcoding810"
artifactId = "android-js"
version = "1.0.0"

pom {
name.set("android-js")
description.set("Rhino wrapper for android kotlin")
url.set("https://github.com/paulcoding810/h-viewer")

licenses {
license {
name.set("The Apache License, Version 2.0")
url.set("http://www.apache.org/licenses/LICENSE-2.0.txt")
}
}

developers {
developer {
id.set("paulcoding810")
name.set("Paul Nguyen")
email.set("paulcoding810@gmail.com")
}
}
}
}
}
}
}
Empty file added js/consumer-rules.pro
Empty file.
Loading
Loading