All Projects → florent37 → WormHole

florent37 / WormHole

Licence: other
WormHole allows to share classes between Flutter and Native Platform (android / ios)

Programming Languages

dart
5743 projects
kotlin
9241 projects
java
68154 projects - #9 most used programming language

Projects that are alternatives of or similar to WormHole

React Native Share
Social share, sending simple data to other apps.
Stars: ✭ 2,955 (+8108.33%)
Mutual labels:  share, bridge
tale-pug
Tale Pug is the popular JavaScript Template Engine Pug, formerly Jade, for PHP!
Stars: ✭ 32 (-11.11%)
Mutual labels:  extend
channel
Go-like channels for JavaScript
Stars: ✭ 49 (+36.11%)
Mutual labels:  channel
FMWebViewJavascriptBridge
FMWebViewJavascriptBridge inspired by WebViewJavascripBridge and react native
Stars: ✭ 29 (-19.44%)
Mutual labels:  bridge
ring-channel
Bounded MPMC channel abstraction on top of a ring buffer
Stars: ✭ 24 (-33.33%)
Mutual labels:  channel
haoide-vscode
haoide-vscode is a vscode extension for salesforce development, which is used to replace haoide
Stars: ✭ 22 (-38.89%)
Mutual labels:  retrieve
Protobuf-Dreamer
A tiled DeepDream project for creating any size of image, on both CPU and GPU
Stars: ✭ 39 (+8.33%)
Mutual labels:  channel
vue-socials
💬 Social media share buttons and counts for Vue.js
Stars: ✭ 32 (-11.11%)
Mutual labels:  share
liu
💫 Boshiamy Input Method in macOS 嘸蝦米輸入法
Stars: ✭ 39 (+8.33%)
Mutual labels:  method
ShareLoginPay
ThirdParty login,share and pay lib
Stars: ✭ 16 (-55.56%)
Mutual labels:  share
filein-frontend
The best way to share files
Stars: ✭ 16 (-55.56%)
Mutual labels:  share
ACVR2017
An Innovative Salient Object Detection Using Center-Dark Channel Prior
Stars: ✭ 20 (-44.44%)
Mutual labels:  channel
ansible-config-interfaces
No description or website provided.
Stars: ✭ 28 (-22.22%)
Mutual labels:  bridge
channelHelper
基于walle工具的多渠道打包脚本
Stars: ✭ 35 (-2.78%)
Mutual labels:  channel
rn-webview-rpc
Add RPC capabilities to a React Native WebView component
Stars: ✭ 25 (-30.56%)
Mutual labels:  bridge
pyphysim
Simulation of Digital Communication (physical layer) in Python.
Stars: ✭ 78 (+116.67%)
Mutual labels:  channel
note
笔记分享 | Note Share
Stars: ✭ 83 (+130.56%)
Mutual labels:  share
no-clipboard-app
Share your clipboard text to your device like Oculus Go.
Stars: ✭ 12 (-66.67%)
Mutual labels:  share
onionfruit
OnionFruit™ Connect - Tor access client with country selection, bridge configuration, pluggable transports and experimental DNS support
Stars: ✭ 150 (+316.67%)
Mutual labels:  bridge
http-method
🍇 Provides constants for HTTP request methods.
Stars: ✭ 83 (+130.56%)
Mutual labels:  method

WormHole

A WormHole is a speculative structure linking disparate points in spacetime.

In a mobile universe, a WormHole is a special solution of the Einstein field equations, enabling to share platform classes to Flutter, and expose Flutter's classes to your native code.

This library has been created to accelerate (integration of flutter on an existing app)[https://github.com/flutter/flutter/wiki/Add-Flutter-to-existing-apps]

But works with an usual flutter apps, if you don't want to bridge manually your native objects using MethodChannels

screen

ShowCase

I want to add a Flutter view inside my existing Native project, this screen needs to retrieve an user, and I use in my project MainRepository

I just have to expose my MainRepository to Flutter through a WormHole !

class MainRepository {
    @Expose("retrieveUser")
    suspend fun retrieveUser() : User {
        return myBDD.getUser()
    }
}

val mainRepository = MainRepository()
expose("user", mainRepository)

Can be retrieved in Flutter

@WormHole
abstract class MainRepository {
    @Call("retrieveUser")
    Future<User> retrieveUser();
    
    factory MainRepository(channelName) => WormHole$MainRepository;
}

final mainRepository = MainRepository("user");
User user = await mainRepository.retrieveUser();

Import

WormHole depends on json_annotation and needs a dart build_runner to run json_serializable and wormhole_generator

dependencies:
  flutter:
    sdk: flutter

  json_annotation: 3.0.0
  wormhole: 1.0.0

dev_dependencies:
  flutter_test:
    sdk: flutter
  build_runner: 1.7.2
  json_serializable: 3.2.3
  wormhole_generator: 1.0.0

Expose on Native, Retrieve on Flutter

screen

Native

  1. Add @Expose("name") on your method, specifying a method name . For async methods, be sure they're implementing coroutine's suspend . For observables results, be sure they're implementing coroutine's Flow
class UserManager(val context: Context) {

    companion object {
        const val USER = "user"
    }

    /**
     * For example, save an user as json into shared preferences
     * Can be a room database, etc.
     */
    private val gson = Gson()
    private val sharedPreferences = context.getSharedPreferences("user_shared", Context.MODE_PRIVATE)
    private val userChannel = ConflatedBroadcastChannel<User?>()

    init {
        updateUser()
    }

    private fun updateUser() {
        val currentUser = sharedPreferences.getString(USER, null)?.let {
            gson.fromJson(it, User::class.java)
        }
        userChannel.offer(currentUser)
    }

    /**
     * A stream exposing the current user
     */
    @Expose("getUser")
    fun getUser(): Flow<User?> = userChannel.asFlow()

    @Expose("saveUser")
    suspend fun saveUser(user: User) {
        sharedPreferences.edit().putString(USER, gson.toJson(user)).apply()
        updateUser()
    }

    @Expose("clear")
    fun clear() {
        sharedPreferences.edit().remove(USER).apply()
        updateUser()
    }
}
  1. Expose this class to a Flutter's element
class MainActivity : FlutterActivity() {

    private val userManager by lazy { UserManager(this) }

    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        GeneratedPluginRegistrant.registerWith(this)

        /**
         * Expose the user manager to be accessible to Flutter via a WormHole
         */
        expose("user", userManager)
    }
}

Flutter

@WormHole()
abstract class UserManager {

  @Call("getUser")
  Stream<User> getUser();

  @Call("saveUser")
  Future<void> saveUser(User user);

  @Call("clear")
  void clear();

  factory UserManager(channelName) => WormHole$UserManager(channelName);
}
  1. Create an abstract class mirroring the Native's element
  2. Annotate it with @WormHole()
  3. For each Native's method, create a Dart method annotated with @Call("methodname") . For async methods, be sure they're returning a Future<type> . For observables results, be sure they're returining a Stream<type>
  4. Create a factory, jumping to WormHole$yourclass(channelName);

Don't forget to run build_runner with flutter pub run build_runner build

final UserManager userManager = UserManager("user");
  1. Then retrieve your native object from the WormHole
StreamBuilder(
    stream: userManager.getUser(),
    builder: (context, snapshot) {
       if (snapshot.hasData && snapshot.data != null) {
         final user = snapshot.data;
         ...
       }
    }
);

And use it as an usual flutter class

Expose on Flutter, Retrieve on Native

screen

Expose on Flutter

@WormHole() //A WormHole will be created arount this class
class QuestionBloc implements Bloc {

  //this method will be exposed to native through a WormHole, using the method name "ask"
  @Expose("ask")
  void ask(Question question) {
    //TODO your code here
  }
  
  expose(channelName) => WormHole$QuestionBloc(channelName).expose(this);
}

I want to expose this object through the wormhole named "question"

final bloc = QuestionBloc();
bloc.expose("question");
  1. Add @WormHole annotation on your class
  2. Add @Expose("name") on your method, specifying a method name
  3. Add an expose method calling WormHole$yourclass("channelName").expose(this)
  4. Expose your object using .expose(channel)

Don't forget to run build_runner with flutter pub run build_runner build

Retrieve on native

interface QuestionBloc {
    @Call("ask")
    fun question(question: Question)
}
  1. Create an interface, containing reflecting your Dart class QuestionBloc
  2. For each @Expose method in Dart, create an @Call method, containing the same method name : ask
//retrieve the Flutter's QuestionBloc, in a FlutterActivity for example
val questionBloc = retrieve<QuestionBloc>("question")
  1. Retrieve an object sent into the wormhole
questionBloc.ask(Question("what's your name"))
  1. Your can now interact with your class

Flutter

WormHole uses annotation processing to Expose/Retrieve Dart through WormHole

See Generator for further explanations and configurations

Android

WormHole uses jvm reflection to Expose/Retrieve Java/Kotlin objects to be accessible through WormHole

See WormHole-Android

iOS

¯\__(ツ)_/¯

WormHole is not available yet on iOS because :

- Annotation Processor does not exists in swift or ObjectiveC

- Reflection on swift does not allow to perform needed actions

- Swift (without ReactiveSwift) does not provides Futures / Streams

If someone in the community has an idea to port it, don't hesitate to make a pull request !

Note that the project description data, including the texts, logos, images, and/or trademarks, for each open source project belongs to its rightful owner. If you wish to add or remove any projects, please contact us at [email protected].