Skip to content

Commit

Permalink
Merge branch 'main' into location-access
Browse files Browse the repository at this point in the history
* main: (63 commits)
  Update to the latest gradle plugin
  Include Turbo Native Android in the user agent substring for backwards compatibilty with existing apps
  Change Turbo Native to Hotwire Native in user agent.
  Update HotwireNavigation.kt
  Remove old docs
  Update README.md
  Revert "Add repositories to each build script"
  Add repositories to each build script
  Disable the gradle configuration cache due to incompatibility with the signing plugin
  Add the signing plugin
  Add Sonatype (Maven Central) publishing support
  Readme updates
  Add publishing build script for the navigation-fragments module
  Remove Strada references
  Update demo site url
  Update android plugin dependencies
  Update CI workflow actions
  Update logo filename
  Update raster launcher icon
  Update vector launcher icon
  ...

# Conflicts:
#	demo/src/main/kotlin/dev/hotwire/demo/features/web/WebFragment.kt
  • Loading branch information
jayohms committed Nov 22, 2024
2 parents d62199a + f75d017 commit 77c0d94
Show file tree
Hide file tree
Showing 195 changed files with 2,876 additions and 3,088 deletions.
27 changes: 27 additions & 0 deletions .github/workflows/sonatype.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
name: Publish to Sonatype

on:
release:
types: [released]

jobs:
publish-release:
runs-on: ubuntu-latest
steps:
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'

- name: Checkout code
uses: actions/checkout@v3

- name: Publish artifact to Sonatype
env:
SONATYPE_USER: ${{ secrets.SONATYPE_USER }}
SONATYPE_PASSWORD: ${{ secrets.SONATYPE_PASSWORD }}
GPG_KEY_ID: ${{ secrets.GPG_KEY_ID }}
GPG_SECRET_KEY: ${{ secrets.GPG_SECRET_KEY }}
GPG_PASSWORD: ${{ secrets.GPG_PASSWORD }}
run: ./gradlew -Psonatype -Pversion=${{ github.event.release.tag_name }} clean build -x test publish
29 changes: 29 additions & 0 deletions .github/workflows/test.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
name: CI

on: [push]

jobs:
test:
runs-on: ubuntu-latest
steps:
- name: Setup Java
uses: actions/setup-java@v3
with:
distribution: 'temurin'
java-version: '17'

- name: Checkout code
uses: actions/checkout@v3

- name: Run lint
run: ./gradlew core:lint

- name: Run tests
run: ./gradlew testRelease

- name: Archive test results
uses: actions/upload-artifact@v4
if: failure()
with:
name: test-results-report
path: core/build/reports/tests/testReleaseUnitTest
File renamed without changes.
32 changes: 32 additions & 0 deletions CONTRIBUTING.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
# Contributing to Hotwire Native Android

Note that we have a [code of conduct](/CODE_OF_CONDUCT.md). Please follow it in your interactions with this project.

## Developing locally

Hotwire Native for Android is built using Kotlin and Android SDK 28+ as its minimum version. To set up your development environment:

1. Clone the repo
1. Open the directory in the latest version of Android Studio

To run the test suite:

1. Open the directory in Terminal
1. Run the `./gradlew testRelease` command

## Sending a Pull Request

The core team is monitoring for pull requests. We will review your pull request and either merge it, request changes to it, or close it with an explanation.

Before submitting a pull request, please:

1. Fork the repository and create your branch.
2. Follow the setup instructions in this file.
3. If you’re fixing a bug or adding code that should be tested, add tests!
4. Ensure the test suite passes.

## Feature parity with Android

New features will not be merged until also added to [Hotwire Native iOS](https://github.com/hotwired/hotwire-native-ios).

This does not apply to bugs that only appear on Android.
38 changes: 7 additions & 31 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,43 +1,19 @@
# Hotwire Native for Android

**Build high-fidelity hybrid apps with native navigation and a single shared web view**. Hotwire Native for Android provides the tooling to wrap your [Turbo 7](https://turbo.hotwired.dev/)-enabled web app in a native Android shell. It manages a single WebView instance across multiple Fragment destinations, giving you native navigation UI with all the client-side performance benefits of Turbo.
![Android SDK](https://img.shields.io/badge/Android%20SDK-28+-green)
![Turbo](https://img.shields.io/badge/Turbo-7+-purple)

## Features
- **Deliver fast, efficient hybrid apps.** Avoid reloading JavaScript and CSS. Save memory by sharing one WebView.
- **Reuse mobile web views across platforms.** Create your views once, on the server, in HTML. Deploy them to [iOS](https://github.com/hotwired/turbo-ios), Android, and mobile browsers simultaneously. Ship new features without waiting on Play Store approval.
- **Enhance web views with native UI.** Navigate web views using native patterns. Augment web UI with native controls.
- **Produce large apps with small teams.** Achieve baseline HTML coverage for free. Upgrade to native views as needed.
[Hotwire Native](https://native.hotwired.dev) is a high-level native framework, available for iOS and Android, that provides you with all the tools you need to leverage your web app and build great mobile apps.

## Requirements
This native Kotlin library integrates with your [Hotwire](https://hotwired.dev) web app by wrapping it in a native Android shell. It manages a single `WebView` instance across multiple destinations, giving you native navigation UI with all the client-side performance benefits of Hotwire.

1. Android SDK 28+ is required as the `minSdk` in your `build.gradle.kts` file.
1. This library is written entirely in [Kotlin](https://kotlinlang.org/), and your app should use Kotlin as well. Compatibility with Java is not provided or supported.
1. This library supports web apps using either Turbo 7 or Turbolinks 5.
1. `Turbo` (or `Turbolinks`) is exposed on the `window` object on the WebView page being loaded.

**Note:** You should understand how Turbo works with web applications in the browser before attempting to use Hotwire Native. See the [Turbo 7 documentation](https://turbo.hotwired.dev) for details.

## Getting Started
The best way to get started with Hotwire Native Android is to try out the demo app first to get familiar with the framework. The demo app walks you through all the basic Turbo flows as well as some advanced features. To run the demo, clone this repo, open the directory in Android Studio, and build the `demo` module to your Android device. See [demo/README.md](demo/README.md) for more details about the demo. When you’re ready to start your own application, read through the rest of the documentation.

See the [instructions to build the project yourself](docs/BUILD-PROJECT.md).

## Documentation

1. [Installation](docs/INSTALLATION.md)
1. [Overview](docs/OVERVIEW.md)
1. [Quick Start](docs/QUICK-START.md)
1. [Path Configuration](docs/PATH-CONFIGURATION.md)
1. [Navigation](docs/NAVIGATION.md)
1. [Advanced Options](docs/ADVANCED-OPTIONS.md)
Read more on [native.hotwired.dev](https://native.hotwired.dev).

## Contributing

Hotwire Native Android is open-source software, freely distributable under the terms of an [MIT-style license](LICENSE). The [source code is hosted on GitHub](https://github.com/hotwired/hotwire-native-android). Development is sponsored by [37signals](https://37signals.com/).

We welcome contributions in the form of bug reports, pull requests, or thoughtful discussions in the [GitHub issue tracker](https://github.com/hotwired/hotwire-native-android/issues).
Hotwire Native for Android is open-source software, freely distributable under the terms of an [MIT-style license](LICENSE). The [source code is hosted on GitHub](https://github.com/hotwired/hotwire-native-bridge). Development is sponsored by [37signals](https://37signals.com/).

Please note that this project is released with a [Contributor Code of Conduct](docs/CONDUCT.md). By participating in this project you agree to abide by its terms.
We welcome contributions in the form of bug reports, pull requests, or thoughtful discussions in the [GitHub issue tracker](https://github.com/hotwired/hotwire-native-bridge/issues).

---------

Expand Down
4 changes: 2 additions & 2 deletions build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
// Top-level build file where you can add configuration options common to all sub-projects/modules.
plugins {
id("com.android.application") version "8.2.2" apply false
id("com.android.library") version "8.2.2" apply false
id("com.android.application") version "8.7.1" apply false
id("com.android.library") version "8.7.1" apply false
id("org.jetbrains.kotlin.android") version "1.9.22" apply false
id("org.jetbrains.kotlin.plugin.serialization") version "1.9.22" apply false
}
Expand Down
90 changes: 61 additions & 29 deletions core/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -3,10 +3,11 @@ plugins {
id("org.jetbrains.kotlin.android")
id("org.jetbrains.kotlin.plugin.serialization")
id("maven-publish")
id("signing")
}

val libVersionName by extra(version as String)
val libraryName by extra("Hotwire Native for Android")
val libraryName by extra("Hotwire Native for Android - Core")
val libraryDescription by extra("Android framework for making Hotwire Native apps")

val publishedGroupId by extra("dev.hotwire")
Expand All @@ -21,15 +22,18 @@ val licenseUrl by extra("https://github.com/hotwired/hotwire-native-android/blob
val developerId by extra("basecamp")
val developerEmail by extra("[email protected]")

val isSonatypeRelease by extra(project.hasProperty("sonatype"))

android {
namespace = "dev.hotwire.core"
compileSdk = 34

testOptions.unitTests.isIncludeAndroidResources = true
testOptions.unitTests.isReturnDefaultValues = true
testOptions.targetSdk = 34

defaultConfig {
minSdk = 28
targetSdk = 34
}

buildTypes {
Expand Down Expand Up @@ -71,56 +75,73 @@ android {

dependencies {
// Kotlin
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.22")
implementation("org.jetbrains.kotlin:kotlin-reflect:1.9.23")

// Material
implementation("com.google.android.material:material:1.11.0")
implementation("com.google.android.material:material:1.12.0")

// AndroidX
implementation("androidx.constraintlayout:constraintlayout:2.1.4")
implementation("androidx.lifecycle:lifecycle-common:2.7.0")
implementation("androidx.lifecycle:lifecycle-common:2.8.1")
implementation("androidx.swiperefreshlayout:swiperefreshlayout:1.1.0")

// JSON
implementation("com.google.code.gson:gson:2.10.1")
implementation("org.jetbrains.kotlinx:kotlinx-serialization-json:1.6.3")

// Networking/API
implementation("com.squareup.okhttp3:okhttp:4.11.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.11.0")
implementation("com.squareup.okhttp3:okhttp:4.12.0")
implementation("com.squareup.okhttp3:logging-interceptor:4.12.0")

// Coroutines
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.7.3")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-android:1.8.0")
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.7.3")

// Browser
implementation("androidx.browser:browser:1.7.0")

// Exported AndroidX dependencies
api("androidx.appcompat:appcompat:1.6.1")
api("androidx.core:core-ktx:1.12.0")
api("androidx.webkit:webkit:1.8.0")
api("androidx.activity:activity-ktx:1.8.1")
api("androidx.fragment:fragment-ktx:1.6.2")
api("androidx.navigation:navigation-fragment-ktx:2.7.5")
api("androidx.navigation:navigation-ui-ktx:2.7.5")
api("androidx.appcompat:appcompat:1.7.0")
api("androidx.core:core-ktx:1.13.1")
api("androidx.webkit:webkit:1.11.0")

// Tests
testImplementation("androidx.test:core:1.5.0") // Robolectric
testImplementation("androidx.navigation:navigation-testing:2.7.5")
testImplementation("androidx.navigation:navigation-testing:2.7.7")
testImplementation("androidx.arch.core:core-testing:2.2.0")
testImplementation("org.jetbrains.kotlinx:kotlinx-coroutines-test:1.7.3")
testImplementation("org.assertj:assertj-core:3.24.2")
testImplementation("org.robolectric:robolectric:4.11.1")
testImplementation("org.mockito:mockito-core:5.2.0")
testImplementation("org.assertj:assertj-core:3.25.3")
testImplementation("org.robolectric:robolectric:4.12.1")
testImplementation("org.mockito:mockito-core:5.11.0")
testImplementation("com.nhaarman:mockito-kotlin:1.6.0")
testImplementation("com.squareup.okhttp3:mockwebserver:4.11.0")
testImplementation("com.squareup.okhttp3:mockwebserver:4.12.0")
testImplementation("junit:junit:4.13.2")
}

tasks {
// Only sign Sonatype release artifacts
withType<Sign>().configureEach {
onlyIf { isSonatypeRelease }
}
}

// Sign Sonatype published release artifacts
if (isSonatypeRelease) {
signing {
val keyId = System.getenv("GPG_KEY_ID")
val secretKey = System.getenv("GPG_SECRET_KEY")
val password = System.getenv("GPG_PASSWORD")

useInMemoryPgpKeys(keyId, secretKey, password)

setRequired({ gradle.taskGraph.hasTask("publish") })
sign(publishing.publications)
}
}

// Publish to GitHub Packages via:
// ./gradlew -Pversion=<version> clean build publish
// https://github.com/orgs/hotwired/packages?repo_name=hotwire-native-android
// Publish to Maven Central via:
// ./gradlew -Psonatype -Pversion=<version> clean build publish
// https://search.maven.org/artifact/dev.hotwire/core
publishing {
publications {
register<MavenPublication>("release") {
Expand Down Expand Up @@ -158,13 +179,24 @@ publishing {
}
}
repositories {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/hotwired/hotwire-native-android")
if (isSonatypeRelease) {
maven {
url = uri("https://s01.oss.sonatype.org/content/repositories/releases/")

credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
credentials {
username = System.getenv("SONATYPE_USER")
password = System.getenv("SONATYPE_PASSWORD")
}
}
} else {
maven {
name = "GitHubPackages"
url = uri("https://maven.pkg.github.com/hotwired/hotwire-native-android")

credentials {
username = System.getenv("GITHUB_ACTOR")
password = System.getenv("GITHUB_TOKEN")
}
}
}
}
Expand Down
4 changes: 2 additions & 2 deletions core/src/main/AndroidManifest.xml
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@
<application>

<provider
android:name=".turbo.util.TurboFileProvider"
android:authorities="${applicationId}.turbo.fileprovider"
android:name=".files.util.HotwireFileProvider"
android:authorities="${applicationId}.hotwire.fileprovider"
android:exported="false"
android:grantUriPermissions="true">
<meta-data
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,7 @@
registerAdapter() {
this.adapterIsRegistered = true

if (this.isStradaAvailable) {
if (this.isBridgeAvailable) {
this.webBridge.setAdapter(this)
} else {
document.addEventListener("web-bridge:ready", () => this.webBridge.setAdapter(this))
Expand All @@ -42,7 +42,7 @@
notifyBridgeOfSupportedComponentsUpdate() {
this.supportedComponentsUpdated()

if (this.isStradaAvailable) {
if (this.isBridgeAvailable) {
this.webBridge.adapterDidUpdateSupportedComponents()
}
}
Expand All @@ -53,7 +53,7 @@

// Reply to web with message
replyWith(message) {
if (this.isStradaAvailable) {
if (this.isBridgeAvailable) {
this.webBridge.receive(JSON.parse(message))
}
}
Expand All @@ -70,20 +70,20 @@
// Native handler

ready() {
StradaNative.bridgeDidInitialize()
BridgeComponentsNative.bridgeDidInitialize()
}

supportedComponentsUpdated() {
StradaNative.bridgeDidUpdateSupportedComponents()
BridgeComponentsNative.bridgeDidUpdateSupportedComponents()
}

postMessage(message) {
StradaNative.bridgeDidReceiveMessage(message)
BridgeComponentsNative.bridgeDidReceiveMessage(message)
}

// Web global

get isStradaAvailable() {
get isBridgeAvailable() {
return window.Strada
}

Expand Down
File renamed without changes.
Loading

0 comments on commit 77c0d94

Please sign in to comment.