leecrossley / cordova-plugin-shake

Cordova / PhoneGap Plugin to detect when a physical device performs a shake gesture
http://ilee.co.uk
92 stars 33 forks source link

cordova-plugin-shake working on Android, but not iOS #36

Open NintendoEngineer opened 4 years ago

NintendoEngineer commented 4 years ago

1. What is the context?

I have built an Ionic 5/Capacitor/React app where I have added the cordova-plugin-shake through capacitor by following the Ionic Docs.

2. What does the code look like?

import React from "react";
import { Subscription } from "rxjs";
import { Shake } from "@ionic-native/shake";

// other stuff...

class MagicEightBall extends React.Component {

  shakeSubscription: Subscription = new Subscription();

  ionViewWillEnter() {
    console.log("Magic8Ball ionViewWillEnter()");
    this.shakeSubscription = Shake.startWatch().subscribe(() => this.onShake());
  }

  onShake() {
    // process shake
  }

}

3. What is the problem?

This works perfectly on Android, but it does not work on iOS. I have made sure the Cordova dependencies have been installed through pod install and that seems to have gone fine. Have been looking for an answer for quite some time now, but I cannot seem to fix it. It has been tested on an iPhone 6S with the latest iOS version as well as on an iPad. The Android version has been run on a Xiaomi Mi 9 and it has worked since the start. Just cannot get it running on iOS.

Any ideas?

Ritzlgrmft commented 4 years ago

I am afraid, the plugin doesn't run out-of-the-box with Capacitor. For getting notified about a shake gesture, on iOS the main controller must register for the motionEnded event. Since Cordova generates the whole main controller by itself, I wrote a hook which patches the generated controller file (see https://github.com/leecrossley/cordova-plugin-shake/blob/master/src/ios/hooks/patchMainViewController.js).

Since you are in Capacitor, you have full control over the iOS code. Therefore it should be easy to add the few lines by yourself.

NintendoEngineer commented 4 years ago

@Ritzlgrmft Thank you for your response! I don't see a MainViewController.m in the compiled version after running ionic capacitor copy ios. There is, however, a CDVViewController.m. I will try it there now and see if it will run. Will keep you updated.

NintendoEngineer commented 4 years ago

@Ritzlgrmft This is what I have in the CDVViewController.m:

@interface CDVViewController () {

}

@property (nonatomic, readwrite, strong) NSMutableDictionary* pluginObjects;

@end

@implementation CDVViewController

// added by cordova-plugin-shake
- (void) motionEnded:(UIEventSubtype)motion withEvent:(UIEvent*)event {
    if (event.type == UIEventTypeMotion && event.subtype == UIEventSubtypeMotionShake) {
    [[NSNotificationCenter defaultCenter] postNotificationName:@"CDVShakeDeviceShaken" object:self];
    }
}

@end

Unfortunately the shaking is still not being registered. From the start XCode has shown CDVShake::startwatch by the way, so I know that subscribing to the event is being picked up.

VeitWeber commented 4 years ago

@NintendoEngineer Did you find a fix for this?

VeitWeber commented 4 years ago

I found a solution by myself. Here's how: https://blog.pikodat.com/2020/07/31/capacitor-and-the-ionic-native-shake-plugin/. Hope it helps.

sneko commented 2 years ago

@VeitWeber thanks for this but in your article it's not clear where the file is located. I made it working by modifying this:

image

But it's inside the Capacitor code... which is not versioned (and probably overwritten sometimes). So it needs to have this inside the pipe, or use npx patch-package to make sure it's always present.

Can you or the others specify what you chose to go with? (maybe I'm modifying the wrong thing...)

Thank you,

rsun11 commented 1 year ago

You can create a new swift file in your app and override CAPBridgeViewController:

image

markalston commented 1 month ago

I was able to get this working by modifying the hook mentioned here #36#issuecomment-647161870 and removing the "Classes" from

var mainViewControllerFile = path.join("platforms", "ios", projectName, "Classes", "MainViewController.m");

as for whatever reason my ionic cordova project using the latest ios platform has MainViewController.m in the project name directory and there is no Classes directory.