Search code examples
angularcapacitor

What is the best approach for separating native features code in web Angular application which is also native android/ios app using Capacitor?


I have question regarding Angular application which is using Capacitor. Our Angular application source code should be used for web build and also for native android/ios applications. Is there some proposed approach which should be followed if we use for example capacitor camera / bluetooth / filesystem native features regarding web application?

How do you separate those native features to not be used on Angular web application? For example, if we're using android app we want that user can upload profile pic from his camera, but if he's using web version we want that he can only upload it from his filesystem. Do you have separate components which are built only for web/native applications or you maybe have condition which validates is user on mobile app or in browser and then use functionalities according to that?

Thank you.


Solution

  • If all three platforms have characteristics that should be taken into account, then I usually create 5 services. An example using the Filesystem plugin:

    1. CapacitorFilesystemService: This is my wrapper service which wraps all calls to the Capacitor plugin. It uses code that should be applied to all three platforms.
    import { Filesystem } from '@capacitor/filesystem';
    ...
    
    @Injectable({
      providedIn: 'root',
    })
    export class CapacitorFilesystemService {
      constructor() {}
    
      public requestPermissions(): Promise<void> {
        try {
          return Filesystem.requestPermissions();
        } catch (error) {
          // e.g. error handling for all platforms
        }
      }
    }
    
    1. CapacitorAndroidFilesystemService: This is the service for Android implementation.
    @Injectable({
      providedIn: 'root',
    })
    export class CapacitorAndroidFilesystemService {
      constructor(
        private capacitorFilesystemService: CapacitorFilesystemService,
      ) {}
    
      public requestPermissions(): Promise<void> {
        // Maybe show a UI hint before asking for permission on Android...
        return this.capacitorFilesystemService.requestPermissions();
      }
    }
    
    1. CapacitorIosFilesystemService: This is the service for iOS implementation.
    @Injectable({
      providedIn: 'root',
    })
    export class CapacitorIosFilesystemService {
      constructor(
        private capacitorFilesystemService: CapacitorFilesystemService,
      ) {}
    
      public requestPermissions(): Promise<void> {
        // More platform specific code...
        return this.capacitorFilesystemService.requestPermissions();
      }
    }
    
    1. CapacitorWebFilesystemService: This is the service for web implementation.
    @Injectable({
      providedIn: 'root',
    })
    export class CapacitorWebFilesystemService {
      constructor(
        private capacitorFilesystemService: CapacitorFilesystemService,
      ) {}
    
      public requestPermissions(): Promise<void> {
        // More platform specific code...
        return this.capacitorFilesystemService.requestPermissions();
      }
    }
    
    1. FilesystemService: This is the service that can now be used by other services to access the filesystem without having to worry about special implementations.
    import { Platform } from '@ionic/angular';
    ...
    
    @Injectable({
      providedIn: 'root',
    })
    export class FilesystemService {
      constructor(
        private capacitorAndroidFilesystemService: CapacitorAndroidFilesystemService,
        private capacitorIosFilesystemService: CapacitorIosFilesystemService,
        private capacitorWebFilesystemService: CapacitorWebFilesystemService,
        private platform: Platform,
      ) {}
    
      public requestPermissions(): Promise<void> {
        if (this.platform.is('android')) {
          return this.capacitorAndroidFilesystemService.requestPermissions();
        } else if (this.platform.is('ios')) {
          return this.capacitorIosFilesystemService.requestPermissions();
        } else {
          return this.capacitorWebFilesystemService.requestPermissions();
        }
      }
    }
    

    However, to be honest, in most cases I don't need a different implementation. So usually the CapacitorFilesystemService and FilesystemService is enough for me. This example is just to explain my approach.