ionic-team / capacitor

Build cross-platform Native Progressive Web Apps for iOS, Android, and the Web ⚡️
https://capacitorjs.com
MIT License
12.02k stars 997 forks source link

bug: Using Capacitor Plugins with WebWorkers for Android app #6309

Closed fegauthier closed 6 months ago

fegauthier commented 1 year ago

Bug Report

Capacitor Version

   Capacitor Doctor   

Latest Dependencies:

  @capacitor/cli: 4.6.3
  @capacitor/core: 4.6.3
  @capacitor/android: 4.6.3
  @capacitor/ios: 4.6.3

Installed Dependencies:

  @capacitor/ios: not installed
  @capacitor/cli: 4.6.3
  @capacitor/core: 4.6.3
  @capacitor/android: 4.6.3

Platform(s)

Android

Current Behavior

I'm using the capacitor plugin SQLite and my own capacitor plugin. Everything is working fine. I want to use capacitor plugins in Web Worker but it doesn't work at all. No call is reaching Android Native.

Expected Behavior

Capacitor plugins should be able to be reached in Web Workers too.

Code Reproduction

This is my worker code. As I mentioned, this code work outside of a Web Worker.

import CategoriesTable from "@/databases/categories.table";
import ConfigTable from "@/databases/config.table";
import { StalkerPortal } from "stalker-portal-capacitor";
import moment from 'moment';
import Promise from 'bluebird';

onmessage = (event) => {
  if(event.data.message === 'start') {
    getCategories(event.data.data);
  }
}

const getCategories = async (data: any) => {
  let theCategories = [];
  //await ConfigTable.deleteByName('LAST_SYNC_CATEGORIES')
  const lastSync = await ConfigTable.findByName('LAST_SYNC_CATEGORIES');

    if(!lastSync) {
      await CategoriesTable.truncate();
      const categoriesString: string = (await StalkerPortal.getCategories({ 
        headers: {},
        cookies: { 
          mac: data.mac, 
          timezone: data.timezone
        },
        data: {
          baseURL: data.portal
        }
      })).value;
      theCategories = JSON.parse(categoriesString).js;
      theCategories.unshift(
        {
          id: 'FAVOURITE',
          title: 'Favourite'
        }
      );
      postMessage({ 
        message: 'progress', 
        data: { 
          total: theCategories.length,
          current: 0,
          step: 'FETCHING_CATEGORIES'
        }
      });
      await Promise.each(theCategories, async (category: any, index: number) => {
        await CategoriesTable.insert(category.id, category.title);
        postMessage({ 
          message: 'progress', 
          data: { 
            current: index + 1,
          }
        })
      });
      await ConfigTable.insertOrReplace('LAST_SYNC_CATEGORIES', moment().format('YYYY-MM-DD HH:mm:ss'));
    }

    postMessage({ 
      message: 'progress', 
      data: { 
        total: theCategories.length,
        current: 0,
        step: 'PROCESSING_CATEGRORIES'
      }
    });
    theCategories = await CategoriesTable.getAll();
    postMessage({ message: 'complete', data: theCategories });
}

Other Technical Details

npm --version output: 9.3.1

node --version output: v18.13.0

pod --version output (iOS issues only):

Additional Context

I tried the hack about putting (<any> self).window = self; at the top of my worker's file but it doesnt' work.

Thanks

Ionitron commented 1 year ago

This issue may need more information before it can be addressed. In particular, it will need a reliable Code Reproduction that demonstrates the issue.

Please see the Contributing Guide for how to create a Code Reproduction.

Thanks! Ionitron 💙

fegauthier commented 1 year ago

Hi guys!

This is my own custom plugin.

StalkerPortalCapacitor.zip

I currently have a Ionic Framework project that use this plugin and it works perfectly. I need to do a lot of calls to my plugin, so I wanted to let web workers doing this kind of job. So I created a Web Worker script that is using my capacitor plugin. I don't know if Capacitor support Web Worker, but when I call my plugin inside the Web Worker plugin, it's like my plugin is null.

This is my web worker script

import CategoriesTable from "@/databases/categories.table";
import ConfigTable from "@/databases/config.table";
import { StalkerPortal } from "stalker-portal-capacitor";
import moment from 'moment';
import Promise from 'bluebird';

onmessage = (event) => {
  if(event.data.message === 'start') {
    getCategories(event.data.data);
  }
}

const getCategories = async (data: any) => {
  let theCategories = [];
  //await ConfigTable.deleteByName('LAST_SYNC_CATEGORIES')
  const lastSync = await ConfigTable.findByName('LAST_SYNC_CATEGORIES');

    if(!lastSync) {
      await CategoriesTable.truncate();
      const categoriesString: string = (await StalkerPortal.getCategories({ 
        headers: {},
        cookies: { 
          mac: data.mac, 
          timezone: data.timezone
        },
        data: {
          baseURL: data.portal
        }
      })).value;
      theCategories = JSON.parse(categoriesString).js;
      theCategories.unshift(
        {
          id: 'FAVOURITE',
          title: 'Favourite'
        }
      );
      postMessage({ 
        message: 'progress', 
        data: { 
          total: theCategories.length,
          current: 0,
          step: 'FETCHING_CATEGORIES'
        }
      });
      await Promise.each(theCategories, async (category: any, index: number) => {
        await CategoriesTable.insert(category.id, category.title);
        postMessage({ 
          message: 'progress', 
          data: { 
            current: index + 1,
          }
        })
      });
      await ConfigTable.insertOrReplace('LAST_SYNC_CATEGORIES', moment().format('YYYY-MM-DD HH:mm:ss'));
    }

    postMessage({ 
      message: 'progress', 
      data: { 
        total: theCategories.length,
        current: 0,
        step: 'PROCESSING_CATEGRORIES'
      }
    });
    theCategories = await CategoriesTable.getAll();
    postMessage({ message: 'complete', data: theCategories });
}
fegauthier commented 1 year ago

The problem is when I use WebWorkers, the platform detected by the framework is Web and not Android. Is it the normal behaviour ?

tachibana-shin commented 1 year ago

The problem is when I use WebWorkers, the platform detected by the framework is Web and not Android. Is it the normal behaviour ?

I had this problem in the past because the capacitor's code didn't inject their apis into the webworker so the only solution was to use the main thread as intermediate sending requests to the main thread and the main thread calling the capacitor. I use plugin @fcanvas/communicate to solve my problem

jcesarmobile commented 6 months ago

Closing since no sample app was provided and the provided plugin is not enough to reproduce.

Capacitor 6 will inject the plugin's javascript into the WebView, so that might have fixed the issue.

If not, please, create a new issue and provide a sample app where the issue can be reproduced.

ionitron-bot[bot] commented 5 months ago

Thanks for the issue! This issue is being locked to prevent comments that are not relevant to the original issue. If this is still an issue with the latest version of Capacitor, please create a new issue and ensure the template is fully filled out.