-
-
Notifications
You must be signed in to change notification settings - Fork 5.1k
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
Mobile: Add support for plugins #9652
Mobile: Add support for plugins #9652
Conversation
…ile-plugin-support/load-jpl-via-expo
**Note**: This replaces the unmaintained `css` package with Adobe's fork, `@adobe/css-tools`. The original `css` package requires the ability to import `fs`, while `@adobe/css-tools` does not.
// TODO: Might not work (and `relative` is broken in path-browserify) | ||
const isSubdirectoryOrSame = (parent: string, possibleChild: string) => { | ||
possibleChild = normalize(possibleChild); | ||
parent = normalize(parent); | ||
|
||
return possibleChild.startsWith(parent); | ||
}; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: Replace with resolvePathWithinDir
once related PR is merged.
…pport/load-jpl-via-expo' into pr/mobile-plugin-support/load-jpl-via-expo
if added while editor is open.
…port/load-jpl-via-expo
…link issue in a better way Fixes the link issue that the previous commits attempted to address. It was caused by injectedJavascript being rerun whenever a hash link was clicked.
@personalizedrefrigerator, please let me know when this is ready to merge (there are few conflicts and the PR is still a draft) |
…port/load-jpl-via-expo
…port/load-jpl-via-expo
Previously, this would generate invalid imports
Closing -- all functionality, except default plugins, has been moved into separate pull requests. |
Summary
This pull request:
jpl
file on mobile.WebView
Demo APK
Plugin settings GUI
What's working
WebView
joplin.views.dialogs.showMessageBox
APIjoplin.plugins.register
APITo-do
.jpl
filesPluginRunner.stop
for desktop?PluginRunner.stop
when a plugin is disabled (rather than requiring an app restart). This reuses the logic that adds support for React Native's fast refresh.postMessage
iframe
(DOM API access & allows us to avoideval
ing plugin code in the main process).webviewApi.postMessage
@joplin/default-plugins
: Added support for building for just one application and refactored default plugins configuration file from JSON to TypeScript.Notes
expo-asset
library is used to load local assets (used to load JPL files)iframe
s within a singleWebView
RemoteMessenger
andtarExtract
were originally created for other pull requestsbuffer
bug to supporttarExtract
Code structure
The below explanation(s) may be converted into files under
readme/dev/spec
.Explanation of
RemoteMessenger
On mobile, not only is the background page running in a separate process, but so are the renderer and dialogs.
To simplify communication between these processes, a
RemoteMessenger
class is introduced.The
RemoteMessenger<LocalInterface, RemoteInterface>
classThe
RemoteMessenger
class simplifies communication overpostMessage
. Its job is to convert asynchronous method calls to messages, then send these messages to anotherRemoteMessenger
that handles them.For example, if we have
We might then create messengers like this:
In the WebView:
In the main process:
To call
messenger.remoteApi.setCss(...)
, we use a process similar to the following:First: Queue the method call and wait for both messengers to be ready.
When a messenger is ready, it sends a message with
kind: RemoteReady
.When a messenger receives a message with
kind: RemoteReady
, it replies with the same message type.Second: Send all queued messages
After both messengers are ready, we wend all queued messages. In this case, that's the
setCss
message:After handling the message, a result is returned also by
postMessage
, this time with thekind
ReturnValueResponse
:After receiving the response, the
setCss
call resolves.On mobile, we address the same problem in similar, but more generalized way. We define a
RemoteMessenger
class that handlespostMessage
communication.RemoteMessenger
and callbacksSuppose we call a method in a way similar to the following:
We can't send callbacks over
postMessage
. As such, we assign theonStart
callback an ID and send the ID instead. The message might look like this:Note: As before, the
respondWithId
connects a method call to its return value (the return value has the same ID).The
arguments.callbacks
object contains only callback IDs and thearguments.serializable
object contains only the serializable arguments. The two objects otherwise should have the same structure. These two objects are merged by theRemoteMessenger
that receives the message:Callbacks are called by sending an
InvokeMethod
message similar to the following:Footnotes
https://developer.apple.com/app-store/review/guidelines/ ↩