@intercom/intercom-react-native
Version:
React Native wrapper to bridge our iOS and Android SDK
131 lines (123 loc) • 6.02 kB
JavaScript
;
Object.defineProperty(exports, "__esModule", {
value: true
});
exports.withAndroidPushNotifications = void 0;
var _path = _interopRequireDefault(require("path"));
var _fs = _interopRequireDefault(require("fs"));
var _configPlugins = require("@expo/config-plugins");
function _interopRequireDefault(e) { return e && e.__esModule ? e : { default: e }; }
const SERVICE_CLASS_NAME = 'IntercomFirebaseMessagingService';
function hasExpoNotifications() {
try {
require('expo-notifications');
return true;
} catch (e) {
return e?.code !== 'MODULE_NOT_FOUND';
}
}
/**
* Generates the Kotlin source for the FirebaseMessagingService that
* forwards FCM tokens and Intercom push messages to the Intercom SDK.
*/
function generateFirebaseServiceKotlin(packageName) {
const extendsExpo = hasExpoNotifications();
const baseClass = extendsExpo ? 'ExpoFirebaseMessagingService' : 'FirebaseMessagingService';
const baseImport = extendsExpo ? 'import expo.modules.notifications.service.ExpoFirebaseMessagingService' : 'import com.google.firebase.messaging.FirebaseMessagingService';
return `package ${packageName}
${baseImport}
import com.google.firebase.messaging.RemoteMessage
import com.intercom.reactnative.IntercomModule
class ${SERVICE_CLASS_NAME} : ${baseClass}() {
override fun onNewToken(refreshedToken: String) {
IntercomModule.sendTokenToIntercom(application, refreshedToken)
super.onNewToken(refreshedToken)
}
override fun onMessageReceived(remoteMessage: RemoteMessage) {
if (IntercomModule.isIntercomPush(remoteMessage)) {
IntercomModule.handleRemotePushMessage(application, remoteMessage)
} else {
super.onMessageReceived(remoteMessage)
}
}
}
`;
}
/**
* Uses withDangerousMod to write the Kotlin FirebaseMessagingService file
* into the app's Android source directory, and ensures firebase-messaging
* is on the app module's compile classpath.
*/
const writeFirebaseService = _config => (0, _configPlugins.withDangerousMod)(_config, ['android', config => {
const packageName = config.android?.package;
if (!packageName) {
throw new Error('@intercom/intercom-react-native: android.package must be defined in your Expo config to use Android push notifications.');
}
const projectRoot = config.modRequest.projectRoot;
const packagePath = packageName.replace(/\./g, '/');
const serviceDir = _path.default.join(projectRoot, 'android', 'app', 'src', 'main', 'java', packagePath);
_fs.default.mkdirSync(serviceDir, {
recursive: true
});
_fs.default.writeFileSync(_path.default.join(serviceDir, `${SERVICE_CLASS_NAME}.kt`), generateFirebaseServiceKotlin(packageName), 'utf-8');
// The native module declares firebase-messaging as an `implementation`
// dependency, which keeps it private to the library. Since our generated
// service lives in the app module, we need firebase-messaging on the
// app's compile classpath too. We read the version from the native
// module's build.gradle so it stays in sync automatically.
const packageRoot = _path.default.resolve(__dirname, '..', '..', '..');
const nativeBuildGradle = _fs.default.readFileSync(_path.default.join(packageRoot, 'android', 'build.gradle'), 'utf-8');
const versionMatch = nativeBuildGradle.match(/com\.google\.firebase:firebase-messaging:([\d.]+)/);
const firebaseMessagingVersion = versionMatch ? versionMatch[1] : '24.1.2';
const buildGradlePath = _path.default.join(projectRoot, 'android', 'app', 'build.gradle');
const buildGradle = _fs.default.readFileSync(buildGradlePath, 'utf-8');
if (!buildGradle.includes('firebase-messaging')) {
const updatedBuildGradle = buildGradle.replace(/dependencies\s*\{/, `dependencies {\n implementation("com.google.firebase:firebase-messaging:${firebaseMessagingVersion}")`);
_fs.default.writeFileSync(buildGradlePath, updatedBuildGradle, 'utf-8');
}
return config;
}]);
const registerServiceInManifest = _config => (0, _configPlugins.withAndroidManifest)(_config, config => {
const mainApplication = _configPlugins.AndroidConfig.Manifest.getMainApplicationOrThrow(config.modResults);
const packageName = config.android?.package;
if (!packageName) {
throw new Error('@intercom/intercom-react-native: android.package must be defined in your Expo config to use Android push notifications.');
}
const serviceName = `.${SERVICE_CLASS_NAME}`;
const existingService = mainApplication.service?.find(s => s.$?.['android:name'] === serviceName);
const hasExistingFcmService = mainApplication.service?.some(s => s.$?.['android:name'] !== serviceName && [].concat(s['intent-filter'] ?? []).some(f => [].concat(f.action ?? []).some(a => a.$?.['android:name'] === 'com.google.firebase.MESSAGING_EVENT')));
if (hasExistingFcmService) {
console.warn('@intercom/intercom-react-native: An existing FirebaseMessagingService was found in AndroidManifest.xml. ' + 'Skipping automatic Intercom service registration to avoid conflicts. ' + 'You will need to route Intercom pushes manually using IntercomModule.isIntercomPush() and IntercomModule.handleRemotePushMessage().');
return config;
}
if (!existingService) {
if (!mainApplication.service) {
mainApplication.service = [];
}
mainApplication.service.push({
'$': {
'android:name': serviceName,
'android:exported': 'false'
},
'intent-filter': [{
$: {
'android:priority': '10'
},
action: [{
$: {
'android:name': 'com.google.firebase.MESSAGING_EVENT'
}
}]
}]
});
}
return config;
});
const withAndroidPushNotifications = (config, props) => {
let newConfig = config;
newConfig = writeFirebaseService(newConfig, props);
newConfig = registerServiceInManifest(newConfig, props);
return newConfig;
};
exports.withAndroidPushNotifications = withAndroidPushNotifications;
//# sourceMappingURL=withAndroidPushNotifications.js.map