Closed mlynch closed 3 years ago
Something to consider are plugins who's API is a 1:1 match for the web API.
Geolocation being one of them, but things like the new media stream plugin
https://github.com/phonegap/phonegap-plugin-media-stream
There's a big push in the plugins to make them follow the spec, I think we should first audit which core plugins follow the web standard and take them into consideration.
@mhartington one question that leaves is how to "activate" those. I think we decided we didn't want to use the cordova browser target, so how else would we load these?
So the code you'd write would be a match for the web API. For example the image capture plugin
https://github.com/phonegap/phonegap-plugin-image-capture
navigator.mediaDevices.getUserMedia({
'audio': true,
'video': {
facingMode: 'user'
}
}).then(function(getmedia) {
var track = getmedia.getVideoTracks()[0];
var imageCapture = new ImageCapture(track);
});
This code matches the actual browser implementation.
https://developer.mozilla.org/en-US/docs/Web/API/MediaStream
So even without cordova, the API will still work, because it's just standard JS
That seems like a nice side effect. What about ones that don't have web analogs? What is the calling convention? That's where I start to question this approach.
I have been kicking around the idea of using stencil components for parts of Ionic Native. Since Stencil components are lazy loaded by default, we can get away with some pretty neat platform-specific things without introducing a lot of code maintenance/overhead.
One of my goals of Ionic Native has always been to support multiple platforms with one API. Namely, cordova, traditional web, and electron with one API. That way, I truly can write once and deploy anywhere.
For the sake of discussion, let's consider the writeFile
API.
If we wanted to support multiple platforms and only load the code actually used for the platform, we could do something like this:
@Component({
tag: 'ion-file-api'
})
export class IonFileAPI implements FileAPI {
@Method writefile(filePath: string, fileContent) {
return writeFileImpl(getPlatform(), filePath, fileContent);
}
}
writeFileImpl(platform: string, filePath: string, fileContent: string) {
const tagName = `${platform}-file-api`;
let element = document.querySelector(tagName);
if (!element) {
// it is doesn't exist, insert it
element = document.createElement(`${platform}-file-api`); // <web-file-api>, <electron-file-api>, <cordova-file-api>
document.body.appendChild(element);
}
// isReady is a utility function that ensures an element is fully hydrated and ready to go before resolving a promise
return isReady(element).then((fileApi) => {
return fileApi.writeFile(filePath, fileContent);
});
}
The ion-file-api
is a component that could be added to the document.body
behind the scenes or directly. This would open the door to using the file api, which is already async by nature.
In the writeFileImpl
method, we append a node dynamically. This node would either be web-file-api
, electron-file-api
, or cordova-file-api
for the sake of argument. When this node hits the DOM, it loads the platform specific code needed to execute and perform the API call.
I could then have two stencil components that look like this:
@Component({
tag: 'web-file-api'
})
export class WebFileApi implements FileAPI {
@Method writeFile(filePath: string, fileContent: string) {
// write to local storage
}
}
@Component({
tag: 'cordova-file-api'
})
export class CordovaFileApi implements FileAPI {
@Method writeFile(filePath: string, fileContent: string) {
// use cordova api
}
}
Where one is used for web, and the other is used for Cordova.
So what is really happening here? Well, first of all, when the ion-file-api
node hits the dom, it begins lazy loading it's own writeFile
implementation. That writeFile
implementation doesn't actually write a file, it just loads another DOM node, and delegate the writing of the file to it. Since everything is async already, the user gets one promise and they're none-the-wiser.
From a developer experience perspective, developer's don't even need to know anything about the DOM or that Ionic native uses it at all.
They could write code like this:
import { File } from '@ionic-native/file';
export class SomeAngularComponent {
ionViewDidEnter() {
File.writeFile('myFilePath.txt', 'someContent');
}
}
In this example, when File.writeFile
is called, it appends the ion-file-api
to the DOM, which in turns appends the worker nodes to the DOM.
I think this approach makes a ton of sense because the developer experience is great, and this would enable us to support multiple platforms with one code base, without adding unnecessary size and complexity to a user's app.
Thanks, Dan
Will further development of Ionic on Angular end someday, soon? My Ionic apps have benefitted from ongoing improvements in Angular and Ionic, but now I am wondering if this is coming to or is at the end.
If I am starting new Ionic apps, phone apps not PWA's, should I be converting to web components strategy?
I appreciate all the great work from Ionic team.
Is there a way to easily disable Ionic Native so it can be packaged in my web deployments without having a hissy fit?
Right now Ionic Native is a bit cumbersome to use for apps that are deployed both to the app store and the web (PWA, etc.).
Ideally, Ionic Native works transparently for plugins with existing implementations on native and the web. Things like Geolocation, Camera, etc.
For ones that don't, we need to make it easy to detect that case and code around it, and also give developers the option to mock data.
Finally, Ionic is moving away from relying on any single frontend framework (like Angular), and instead moving to standard web components and vanilla JS APIs. The current injectable dependence makes that hard.
A Proposal
To support Web APIs, given that cordova browser is probably not a workable solution for Ionic PWAs/web stuff, we will have a web implementation for each plugin that has one. To the user, this will be seamless.
To move away from classes and injectables, it might be nice to move to a functional approach, so a plugin like Geolocation would look like this (pseudocode):
And then
pluginFunction
contains the logic for proxying to Cordova/Native layer (might be different on electron, for example), as well as making it easy to provide default data or a callback to handle when Cordova isn't available but there's no web API available:Consider this the start of a discussion, would love thoughts and ideas.
cc @danbucholtz @ihadeed @jgw96 @mhartington