UNPKG

@bigin/ns-firebase

Version:
1,185 lines (1,181 loc) 91.9 kB
import { Application, Utils, AndroidApplication } from '@nativescript/core'; import lazy from '@nativescript/core/utils/lazy'; import { DocumentSnapshot as DocumentSnapshotBase, FieldValue, firebase, GeoPoint, isDocumentReference } from './firebase-common'; import * as firebaseFunctions from './functions/functions'; import * as firebaseMessaging from './messaging/messaging'; export var QueryOrderByType; (function (QueryOrderByType) { QueryOrderByType[(QueryOrderByType['KEY'] = 0)] = 'KEY'; QueryOrderByType[(QueryOrderByType['VALUE'] = 1)] = 'VALUE'; QueryOrderByType[(QueryOrderByType['CHILD'] = 2)] = 'CHILD'; QueryOrderByType[(QueryOrderByType['PRIORITY'] = 3)] = 'PRIORITY'; })(QueryOrderByType || (QueryOrderByType = {})); export var QueryRangeType; (function (QueryRangeType) { QueryRangeType[(QueryRangeType['START_AT'] = 0)] = 'START_AT'; QueryRangeType[(QueryRangeType['END_AT'] = 1)] = 'END_AT'; QueryRangeType[(QueryRangeType['EQUAL_TO'] = 2)] = 'EQUAL_TO'; })(QueryRangeType || (QueryRangeType = {})); export var QueryLimitType; (function (QueryLimitType) { QueryLimitType[(QueryLimitType['FIRST'] = 0)] = 'FIRST'; QueryLimitType[(QueryLimitType['LAST'] = 1)] = 'LAST'; })(QueryLimitType || (QueryLimitType = {})); const gmsAds = com.google.android.gms.ads; const gmsTasks = com.google.android.gms.tasks; class DocumentSnapshot extends DocumentSnapshotBase { constructor(snapshot) { super(snapshot ? snapshot.getId() : null, snapshot.exists(), firebase.toJsObject(snapshot.getData()), firebase.firestore._getDocumentReference(snapshot.getReference())); this.snapshot = snapshot; this.metadata = { fromCache: this.snapshot.getMetadata().isFromCache(), hasPendingWrites: this.snapshot.getMetadata().hasPendingWrites(), }; this.android = snapshot; } } firebase._launchNotification = null; firebase._cachedDynamicLink = null; firebase._googleSignInIdToken = null; firebase._googleSignInAuthCode = null; firebase._facebookAccessToken = null; firebase._appleSignInIdToken = null; let fbCallbackManager = null; let initializeArguments; const GOOGLE_SIGNIN_INTENT_ID = 123; const authEnabled = lazy(() => typeof com.google.firebase.auth !== 'undefined' && typeof com.google.firebase.auth.FirebaseAuth !== 'undefined'); const messagingEnabled = lazy(() => typeof com.google.firebase.messaging !== 'undefined'); const dynamicLinksEnabled = lazy(() => typeof com.google.firebase.dynamiclinks !== 'undefined'); (() => { Application.android.on(AndroidApplication.activityCreatedEvent, (args) => { if (messagingEnabled()) { firebaseMessaging.onAppModuleLaunchEvent(args.activity.getIntent()); } // if (dynamicLinksEnabled()) { // const emailLink = '' + args.activity.getIntent().getData(); // if (authEnabled() && com.google.firebase.auth.FirebaseAuth.getInstance().isSignInWithEmailLink(emailLink)) { // const rememberedEmail = firebase.getRememberedEmailForEmailLinkLogin(); // if (rememberedEmail !== undefined) { // const emailLinkOnCompleteListener = new gmsTasks.OnCompleteListener({ // onComplete: (task) => { // if (task.isSuccessful()) { // const authResult = task.getResult(); // firebase.notifyAuthStateListeners({ // loggedIn: true, // user: toLoginResult(authResult.getUser(), authResult.getAdditionalUserInfo()), // }); // } // }, // }); // const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); // if (user) { // const authCredential = com.google.firebase.auth.EmailAuthProvider.getCredentialWithLink(rememberedEmail, emailLink); // user.linkWithCredential(authCredential).addOnCompleteListener(emailLinkOnCompleteListener); // } else { // com.google.firebase.auth.FirebaseAuth.getInstance().signInWithEmailLink(rememberedEmail, emailLink).addOnCompleteListener(emailLinkOnCompleteListener); // } // } // } else { // const getDynamicLinksCallback = new gmsTasks.OnSuccessListener({ // onSuccess: (pendingDynamicLinkData) => { // if (pendingDynamicLinkData != null) { // const deepLink = pendingDynamicLinkData.getLink().toString(); // const minimumAppVersion = pendingDynamicLinkData.getMinimumAppVersion(); // if (firebase._dynamicLinkCallback === null) { // firebase._cachedDynamicLink = { // url: deepLink, // minimumAppVersion: minimumAppVersion, // }; // } else { // setTimeout(function () { // firebase._dynamicLinkCallback({ // url: deepLink, // minimumAppVersion: minimumAppVersion, // }); // }); // } // } // }, // }); // const firebaseDynamicLinks = com.google.firebase.dynamiclinks.FirebaseDynamicLinks.getInstance(); // firebaseDynamicLinks.getDynamicLink(args.activity.getIntent()).addOnSuccessListener(getDynamicLinksCallback); // } // } }); Application.android.on(AndroidApplication.activityResumedEvent, (args) => { if (dynamicLinksEnabled()) { const emailLink = '' + args.activity.getIntent().getData(); if (authEnabled() && com.google.firebase.auth.FirebaseAuth.getInstance().isSignInWithEmailLink(emailLink)) { const rememberedEmail = firebase.getRememberedEmailForEmailLinkLogin(); if (rememberedEmail !== undefined) { const emailLinkOnCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (task.isSuccessful()) { const authResult = task.getResult(); firebase.notifyAuthStateListeners({ loggedIn: true, user: toLoginResult(authResult.getUser(), authResult.getAdditionalUserInfo()), }); } }, }); const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user) { const authCredential = com.google.firebase.auth.EmailAuthProvider.getCredentialWithLink(rememberedEmail, emailLink); user.linkWithCredential(authCredential).addOnCompleteListener(emailLinkOnCompleteListener); } else { com.google.firebase.auth.FirebaseAuth.getInstance().signInWithEmailLink(rememberedEmail, emailLink).addOnCompleteListener(emailLinkOnCompleteListener); } } } else { const getDynamicLinksCallback = new gmsTasks.OnSuccessListener({ onSuccess: (pendingDynamicLinkData) => { if (pendingDynamicLinkData != null) { const deepLink = pendingDynamicLinkData.getLink().toString(); const minimumAppVersion = pendingDynamicLinkData.getMinimumAppVersion(); // if (!firebase._cachedDynamicLink) { // firebase._cachedDynamicLink = { // url: '', // minimumAppVersion: '', // }; // } if (firebase._dynamicLinkCallback === null) { firebase._cachedDynamicLink = { url: deepLink, minimumAppVersion: minimumAppVersion, }; } else { if (firebase._cachedDynamicLink === null || firebase._cachedDynamicLink.url !== deepLink) { setTimeout(function () { firebase._cachedDynamicLink = { url: deepLink, minimumAppVersion: minimumAppVersion, }; firebase._dynamicLinkCallback({ url: deepLink, minimumAppVersion: minimumAppVersion, }); }); } } } }, }); const firebaseDynamicLinks = com.google.firebase.dynamiclinks.FirebaseDynamicLinks.getInstance(); firebaseDynamicLinks.getDynamicLink(args.activity.getIntent()).addOnSuccessListener(getDynamicLinksCallback); } } }); Application.on(Application.resumeEvent, (args) => { if (messagingEnabled()) { firebaseMessaging.onAppModuleResumeEvent(args); } }); })(); firebase.toHashMap = (obj) => { const node = new java.util.HashMap(); for (const property in obj) { if (obj.hasOwnProperty(property)) { if (obj[property] === null) { node.put(property, null); } else { if (obj[property] === 'SERVER_TIMESTAMP') { node.put(property, com.google.firebase.firestore.FieldValue.serverTimestamp()); } else if (obj[property] === 'DELETE_FIELD') { node.put(property, com.google.firebase.firestore.FieldValue.delete()); } else if (obj[property] instanceof FieldValue) { const fieldValue = obj[property]; if (fieldValue.type === 'ARRAY_UNION') { let values = Array.isArray(fieldValue.value[0]) ? fieldValue.value[0] : fieldValue.value; values = values.map((v) => (typeof v === 'object' ? firebase.toHashMap(v) : v)); node.put(property, com.google.firebase.firestore.FieldValue.arrayUnion(values)); } else if (fieldValue.type === 'ARRAY_REMOVE') { let values = Array.isArray(fieldValue.value[0]) ? fieldValue.value[0] : fieldValue.value; values = values.map((v) => (typeof v === 'object' ? firebase.toHashMap(v) : v)); node.put(property, com.google.firebase.firestore.FieldValue.arrayRemove(values)); } else if (fieldValue.type === 'INCREMENT') { node.put(property, com.google.firebase.firestore.FieldValue.increment(fieldValue.value)); } else { console.log("You found a bug! Please report an issue at https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues, mention fieldValue.type = '" + fieldValue.type + "'. Thanks!"); } } else if (obj[property] instanceof Date) { node.put(property, new java.util.Date(obj[property].getTime())); } else if (obj[property] instanceof GeoPoint) { const geo = obj[property]; node.put(property, new com.google.firebase.firestore.GeoPoint(geo.latitude, geo.longitude)); } else if (isDocumentReference(obj[property])) { node.put(property, obj[property].android); } else if (Array.isArray(obj[property])) { node.put(property, firebase.toJavaArray(obj[property])); } else { switch (typeof obj[property]) { case 'object': node.put(property, firebase.toHashMap(obj[property], node)); break; case 'boolean': node.put(property, java.lang.Boolean.valueOf(String(obj[property]))); break; case 'number': if (Number(obj[property]) === obj[property] && obj[property] % 1 === 0) node.put(property, java.lang.Long.valueOf(String(obj[property]))); else node.put(property, java.lang.Double.valueOf(String(obj[property]))); break; case 'string': node.put(property, String(obj[property])); break; } } } } } return node; }; firebase.toJavaArray = (val) => { const javaArray = new java.util.ArrayList(); for (let i = 0; i < val.length; i++) { javaArray.add(firebase.toValue(val[i])); } return javaArray; }; firebase.toValue = (val) => { let returnVal = null; if (val !== null) { if (val instanceof Date) { returnVal = new java.util.Date(val.getTime()); } else if (Array.isArray(val)) { returnVal = firebase.toJavaArray(val); } else if (val instanceof GeoPoint) { returnVal = new com.google.firebase.firestore.GeoPoint(val.latitude, val.longitude); } else if (isDocumentReference(val)) { returnVal = val.android; } else { switch (typeof val) { case 'object': returnVal = firebase.toHashMap(val); break; case 'boolean': returnVal = java.lang.Boolean.valueOf(String(val)); break; case 'number': if (Number(val) === val && val % 1 === 0) returnVal = java.lang.Long.valueOf(String(val)); else returnVal = java.lang.Double.valueOf(String(val)); break; case 'string': returnVal = String(val); break; } } } return returnVal; }; firebase.toJsObject = (javaObj) => { if (javaObj === null || typeof javaObj !== 'object') { return javaObj; } let node; switch (javaObj.getClass().getName()) { case 'java.lang.Boolean': const str = String(javaObj); return Boolean(!!(str === 'True' || str === 'true')); case 'java.lang.String': return String(javaObj); case 'java.lang.Integer': case 'java.lang.Long': case 'java.lang.Double': return Number(String(javaObj)); case 'java.util.Date': return new Date(javaObj.getTime()); case 'com.google.firebase.Timestamp': return new Date(javaObj.toDate().getTime()); case 'com.google.firebase.firestore.GeoPoint': return { latitude: javaObj.getLatitude(), longitude: javaObj.getLongitude(), }; case 'com.google.firebase.firestore.DocumentReference': const path = javaObj.getPath(); const lastSlashIndex = path.lastIndexOf('/'); return firebase.firestore._getDocumentReference(javaObj, path.substring(0, lastSlashIndex), path.substring(lastSlashIndex + 1)); case 'java.util.ArrayList': node = []; for (let i = 0; i < javaObj.size(); i++) { node[i] = firebase.toJsObject(javaObj.get(i)); } break; case 'android.util.ArrayMap': case 'android.support.v4.util.ArrayMap': case 'androidx.collection.ArrayMap': node = {}; for (let i = 0; i < javaObj.size(); i++) { node[javaObj.keyAt(i)] = firebase.toJsObject(javaObj.valueAt(i)); } break; default: try { node = {}; const iterator = javaObj.entrySet().iterator(); while (iterator.hasNext()) { const item = iterator.next(); node[item.getKey()] = firebase.toJsObject(item.getValue()); } } catch (e) { if (JSON.stringify(e).includes('Attempt to use cleared object reference')) { console.log('Error while transforming Java to Js: ' + e); } else { console.log('PLEASE REPORT THIS AT https://github.com/EddyVerbruggen/nativescript-plugin-firebase/issues: Tried to serialize an unsupported type: ' + javaObj.getClass().getName() + ', error: ' + e); } } } return node; }; firebase.getCallbackData = (type, snapshot) => { return { type: type, key: snapshot.getKey(), value: firebase.toJsObject(snapshot.getValue()), }; }; firebase.authStateListener = null; firebase.init = (arg) => { return new Promise((resolve, reject) => { if (firebase.initialized) { reject('Firebase already initialized'); return; } firebase.initialized = true; const runInit = () => { arg = arg || {}; initializeArguments = arg; if (typeof com.google.firebase.analytics !== 'undefined' && typeof com.google.firebase.analytics.FirebaseAnalytics !== 'undefined') { com.google.firebase.analytics.FirebaseAnalytics.getInstance(Application.android.context || Application.getNativeApplication()).setAnalyticsCollectionEnabled(arg.analyticsCollectionEnabled !== false); } if (arg.crashlyticsCollectionEnabled && typeof com.crashlytics !== 'undefined' && typeof com.crashlytics.android.Crashlytics !== 'undefined') { io.fabric.sdk.android.Fabric.with(Application.android.context || Application.getNativeApplication(), [new com.crashlytics.android.Crashlytics()]); } if (typeof com.google.firebase.database !== 'undefined' && typeof com.google.firebase.database.ServerValue !== 'undefined') { firebase.ServerValue = { TIMESTAMP: firebase.toJsObject(com.google.firebase.database.ServerValue.TIMESTAMP), }; const fDatabase = com.google.firebase.database.FirebaseDatabase; if (arg.persist) { try { fDatabase.getInstance().setPersistenceEnabled(true); } catch (ignore) {} } firebase.instance = fDatabase.getInstance().getReference(); } if (arg.persist === false && typeof com.google.firebase.firestore !== 'undefined') { try { com.google.firebase.firestore.FirebaseFirestore.getInstance().setFirestoreSettings(new com.google.firebase.firestore.FirebaseFirestoreSettings.Builder().setPersistenceEnabled(false).build()); } catch (ignore) {} } if (authEnabled()) { const firebaseAuth = com.google.firebase.auth.FirebaseAuth.getInstance(); if (arg.onAuthStateChanged) { firebase.addAuthStateListener(arg.onAuthStateChanged); } if (!firebase.authStateListener) { firebase.authStateListener = new com.google.firebase.auth.FirebaseAuth.AuthStateListener({ onAuthStateChanged: (fbAuth) => { const user = fbAuth.getCurrentUser(); firebase.notifyAuthStateListeners({ loggedIn: user !== null, user: toLoginResult(user), }); }, }); firebaseAuth.addAuthStateListener(firebase.authStateListener); } } if (messagingEnabled()) { firebaseMessaging.initFirebaseMessaging(arg); } if (arg.onDynamicLinkCallback !== undefined) { firebase.addOnDynamicLinkReceivedCallback(arg.onDynamicLinkCallback); } if (arg.storageBucket) { if (typeof com.google.firebase.storage === 'undefined') { reject("Uncomment firebase-storage in the plugin's include.gradle first"); return; } firebase.storageBucket = com.google.firebase.storage.FirebaseStorage.getInstance().getReferenceFromUrl(arg.storageBucket); } if (typeof gmsAds !== 'undefined' && typeof gmsAds.MobileAds !== 'undefined') { gmsAds.MobileAds.initialize(Application.android.context); } resolve(firebase.instance); }; try { if (Application.android.startActivity) { runInit(); } else { Application.on(Application.launchEvent, runInit); } } catch (ex) { console.log('Error in firebase.init: ' + ex); reject(ex); } }); }; firebase.fetchSignInMethodsForEmail = (email) => { return new Promise((resolve, reject) => { try { if (typeof email !== 'string') { reject('A parameter representing an email address is required.'); return; } const onCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { const signInMethods = task.getResult().getSignInMethods(); resolve(firebase.toJsObject(signInMethods)); } }, }); com.google.firebase.auth.FirebaseAuth.getInstance().fetchSignInMethodsForEmail(email).addOnCompleteListener(onCompleteListener); } catch (ex) { console.log('Error in firebase.fetchSignInMethodsForEmail: ' + ex); reject(ex); } }); }; firebase.getCurrentPushToken = firebaseMessaging.getCurrentPushToken; firebase.addOnMessageReceivedCallback = firebaseMessaging.addOnMessageReceivedCallback; firebase.addOnPushTokenReceivedCallback = firebaseMessaging.addOnPushTokenReceivedCallback; firebase.registerForPushNotifications = firebaseMessaging.registerForPushNotifications; firebase.unregisterForPushNotifications = firebaseMessaging.unregisterForPushNotifications; firebase.subscribeToTopic = firebaseMessaging.subscribeToTopic; firebase.unsubscribeFromTopic = firebaseMessaging.unsubscribeFromTopic; firebase.areNotificationsEnabled = firebaseMessaging.areNotificationsEnabled; firebase.functions = firebaseFunctions; firebase.addOnDynamicLinkReceivedCallback = (callback) => { return new Promise((resolve, reject) => { try { if (typeof com.google.firebase.dynamiclinks === 'undefined') { reject("Uncomment dynamic links in the plugin's include.gradle first"); return; } firebase._dynamicLinkCallback = callback; if (firebase._cachedDynamicLink !== null) { callback(firebase._cachedDynamicLink); // firebase._cachedDynamicLink = null; } resolve(); } catch (ex) { console.log('Error in firebase.addOnDynamicLinkReceivedCallback: ' + ex); reject(ex); } }); }; firebase.getRemoteConfigDefaults = (properties) => { let defaults = {}; for (const p in properties) { const prop = properties[p]; if (prop.default !== undefined) { defaults[prop.key] = prop.default; } } return defaults; }; firebase._isGooglePlayServicesAvailable = () => { const ctx = Application.android.foregroundActivity || Application.android.startActivity || Application.getNativeApplication(); const googleApiAvailability = com.google.android.gms.common.GoogleApiAvailability.getInstance(); const playServiceStatusSuccess = 0; const playServicesStatus = googleApiAvailability.isGooglePlayServicesAvailable(ctx); const available = playServicesStatus === playServiceStatusSuccess; if (!available && googleApiAvailability.isUserResolvableError(playServicesStatus)) { googleApiAvailability.showErrorDialogFragment( ctx, playServicesStatus, 1, new android.content.DialogInterface.OnCancelListener({ onCancel: (dialogInterface) => { console.log('Canceled'); }, }) ); } return available; }; firebase.getRemoteConfig = (arg) => { return new Promise((resolve, reject) => { if (typeof com.google.firebase.remoteconfig === 'undefined') { reject("Uncomment firebase-config in the plugin's include.gradle first"); return; } if (arg.properties === undefined) { reject("Argument 'properties' is missing"); return; } const runGetRemoteConfig = () => { if (!firebase._isGooglePlayServicesAvailable()) { reject('Google Play services is required for this feature, but not available on this device'); return; } const firebaseRemoteConfig = com.google.firebase.remoteconfig.FirebaseRemoteConfig.getInstance(); const remoteConfigSettingsBuilder = new com.google.firebase.remoteconfig.FirebaseRemoteConfigSettings.Builder(); if (arg.developerMode === true) { remoteConfigSettingsBuilder.setFetchTimeoutInSeconds(0); } const onSetConfigSettingsCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { const defaults = firebase.getRemoteConfigDefaults(arg.properties); firebaseRemoteConfig.setDefaultsAsync(firebase.toHashMap(defaults)).addOnCompleteListener( new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { const returnMethod = (throttled) => { const addOnCompleteActivateListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { const lastFetchTime = firebaseRemoteConfig.getInfo().getFetchTimeMillis(); const lastFetch = new Date(lastFetchTime); const result = { lastFetch, throttled, properties: {}, }; for (const p in arg.properties) { const prop = arg.properties[p]; const key = prop.key; const value = firebaseRemoteConfig.getString(key); result.properties[key] = firebase.strongTypeify(value); } resolve(result); } }, }); firebaseRemoteConfig.activate().addOnCompleteListener(addOnCompleteActivateListener); }; const onSuccessListener = new gmsTasks.OnSuccessListener({ onSuccess: () => returnMethod(false), }); const onFailureListener = new gmsTasks.OnFailureListener({ onFailure: (exception) => { if (exception.getMessage() === 'com.google.firebase.remoteconfig.FirebaseRemoteConfigFetchThrottledException') { returnMethod(true); } else { reject('Retrieving remote config data failed. ' + exception); } }, }); const expirationDuration = arg.cacheExpirationSeconds || 43200; firebaseRemoteConfig.fetch(expirationDuration).addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener); } }, }) ); } }, }); firebaseRemoteConfig.setConfigSettingsAsync(remoteConfigSettingsBuilder.build()).addOnCompleteListener(onSetConfigSettingsCompleteListener); }; try { if (Application.android.foregroundActivity) { runGetRemoteConfig(); } else { const callback = () => { runGetRemoteConfig(); Application.off(Application.resumeEvent, callback); }; Application.on(Application.resumeEvent, callback); } } catch (ex) { console.log('Error in firebase.getRemoteConfig: ' + ex); reject(ex); } }); }; firebase.getCurrentUser = (arg) => { return new Promise((resolve, reject) => { try { const firebaseAuth = com.google.firebase.auth.FirebaseAuth.getInstance(); const user = firebaseAuth.getCurrentUser(); if (user !== null) { resolve(toLoginResult(user)); } else { reject(); } } catch (ex) { console.log('Error in firebase.getCurrentUser: ' + ex); reject(ex); } }); }; firebase.sendEmailVerification = (actionCodeSettings) => { return new Promise((resolve, reject) => { try { const firebaseAuth = com.google.firebase.auth.FirebaseAuth.getInstance(); const user = firebaseAuth.getCurrentUser(); if (user !== null) { const addOnCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { resolve(); } }, }); if (actionCodeSettings) { const settingsBuilder = new com.google.firebase.auth.ActionCodeSettings.newBuilder(); if (actionCodeSettings.handleCodeInApp !== undefined) { settingsBuilder.setHandleCodeInApp(actionCodeSettings.handleCodeInApp); } if (actionCodeSettings.url) { settingsBuilder.setUrl(actionCodeSettings.url); } if (actionCodeSettings.iOS && actionCodeSettings.iOS.bundleId) { settingsBuilder.setIOSBundleId(actionCodeSettings.iOS.bundleId); } if (actionCodeSettings.android && actionCodeSettings.android.packageName) { settingsBuilder.setAndroidPackageName(actionCodeSettings.android.packageName, actionCodeSettings.android.installApp, actionCodeSettings.android.minimumVersion || null); } user.sendEmailVerification(settingsBuilder.build()).addOnCompleteListener(addOnCompleteListener); } else { user.sendEmailVerification().addOnCompleteListener(addOnCompleteListener); } } else { reject('Log in first'); } } catch (ex) { console.log('Error in firebase.sendEmailVerification: ' + ex); reject(ex); } }); }; firebase.logout = (arg) => { return new Promise((resolve, reject) => { try { com.google.firebase.auth.FirebaseAuth.getInstance().signOut(); firebase.currentAdditionalUserInfo = null; if (firebase._mGoogleApiClient && firebase._mGoogleApiClient.isConnected()) { com.google.android.gms.auth.api.Auth.GoogleSignInApi.revokeAccess(firebase._mGoogleApiClient); } if (typeof com.facebook !== 'undefined' && typeof com.facebook.login !== 'undefined') { com.facebook.login.LoginManager.getInstance().logOut(); } resolve(); } catch (ex) { console.log('Error in firebase.logout: ' + ex); reject(ex); } }); }; firebase.unlink = (providerId) => { return new Promise((resolve, reject) => { try { const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (!user) { reject('Not logged in'); return; } user.unlink(providerId).addOnCompleteListener( new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (task.isSuccessful()) { resolve(); } else { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } }, }) ); } catch (ex) { console.log('Error in firebase.unlink: ' + ex); reject(ex); } }); }; firebase.getAuthToken = (arg) => { return new Promise((resolve, reject) => { try { const firebaseAuth = com.google.firebase.auth.FirebaseAuth.getInstance(); const user = firebaseAuth.getCurrentUser(); if (user !== null) { const onSuccessListener = new gmsTasks.OnSuccessListener({ onSuccess: (tokenResult) => { resolve({ token: tokenResult.getToken(), claims: firebase.toJsObject(tokenResult.getClaims()), signInProvider: tokenResult.getSignInProvider(), expirationTime: tokenResult.getExpirationTimestamp(), issuedAtTime: tokenResult.getIssuedAtTimestamp(), authTime: tokenResult.getAuthTimestamp(), }); }, }); const onFailureListener = new gmsTasks.OnFailureListener({ onFailure: (exception) => { reject(exception); }, }); user.getIdToken(arg.forceRefresh).addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener); } else { reject('Log in first'); } } catch (ex) { console.log('Error in firebase.getAuthToken: ' + ex); reject(ex); } }); }; function toLoginResult(user, additionalUserInfo) { if (user === null) { return null; } if (additionalUserInfo) { firebase.currentAdditionalUserInfo = additionalUserInfo; } const providers = []; const providerData = user.getProviderData(); for (let i = 0; i < providerData.size(); i++) { const pid = providerData.get(i).getProviderId(); if (pid === 'facebook.com') { providers.push({ id: pid, token: firebase._facebookAccessToken }); } else if (pid === 'google.com') { providers.push({ id: pid, token: firebase._googleSignInAuthCode }); } else if (pid === 'apple.com') { providers.push({ id: pid, token: firebase._appleSignInIdToken }); } else { providers.push({ id: pid }); } } const loginResult = { uid: user.getUid(), displayName: user.getDisplayName(), email: user.getEmail(), emailVerified: user.isEmailVerified(), providers: providers, anonymous: user.isAnonymous(), isAnonymous: user.isAnonymous(), phoneNumber: user.getPhoneNumber(), photoURL: user.getPhotoUrl() ? user.getPhotoUrl().toString() : null, metadata: { creationTimestamp: user.getMetadata() ? new Date(user.getMetadata().getCreationTimestamp()) : null, lastSignInTimestamp: user.getMetadata() ? new Date(user.getMetadata().getLastSignInTimestamp()) : null, }, getIdToken: (forceRefresh) => new Promise((resolve, reject) => { firebase .getAuthToken({ forceRefresh }) .then((result) => resolve(result.token)) .catch(reject); }), getIdTokenResult: (forceRefresh) => new Promise((resolve, reject) => { firebase .getAuthToken({ forceRefresh }) .then((result) => resolve(result)) .catch(reject); }), sendEmailVerification: (actionCodeSettings) => firebase.sendEmailVerification(actionCodeSettings), }; if (firebase.currentAdditionalUserInfo) { loginResult.additionalUserInfo = { providerId: firebase.currentAdditionalUserInfo.getProviderId(), username: firebase.currentAdditionalUserInfo.getUsername(), isNewUser: firebase.currentAdditionalUserInfo.isNewUser(), profile: firebase.toJsObject(firebase.currentAdditionalUserInfo.getProfile()), }; } return loginResult; } firebase.login = (arg) => { return new Promise((resolve, reject) => { try { firebase.resolve = resolve; firebase.reject = reject; if (!firebase._isGooglePlayServicesAvailable()) { reject('Google Play services is required for this feature, but not available on this device'); return; } firebase.moveLoginOptionsToObjects(arg); const firebaseAuth = com.google.firebase.auth.FirebaseAuth.getInstance(); const onCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { console.log('Logging in the user failed. ' + (task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException())); if (firebase._mGoogleApiClient) { com.google.android.gms.auth.api.Auth.GoogleSignInApi.revokeAccess(firebase._mGoogleApiClient); } if (firebase.reject) { firebase.reject('Logging in the user failed. ' + (task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException())); } } else { const user = task.getResult().getUser(); let additionalUserInfo = task.getResult().getAdditionalUserInfo(); if (firebase.resolve) { firebase.resolve(toLoginResult(user, additionalUserInfo)); } } }, }); if (arg.type === firebase.LoginType.ANONYMOUS) { firebaseAuth.signInAnonymously().addOnCompleteListener(onCompleteListener); } else if (arg.type === firebase.LoginType.PASSWORD) { if (!arg.passwordOptions || !arg.passwordOptions.email || !arg.passwordOptions.password) { reject("Auth type PASSWORD requires an 'passwordOptions.email' and 'passwordOptions.password' argument"); return; } const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user) { if (firebase._alreadyLinkedToAuthProvider(user, 'password')) { firebaseAuth.signInWithEmailAndPassword(arg.passwordOptions.email, arg.passwordOptions.password).addOnCompleteListener(onCompleteListener); } else { const authCredential = com.google.firebase.auth.EmailAuthProvider.getCredential(arg.passwordOptions.email, arg.passwordOptions.password); user.linkWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } } else { firebaseAuth.signInWithEmailAndPassword(arg.passwordOptions.email, arg.passwordOptions.password).addOnCompleteListener(onCompleteListener); } } else if (arg.type === firebase.LoginType.EMAIL_LINK) { if (!arg.emailLinkOptions || !arg.emailLinkOptions.email) { reject("Auth type EMAIL_LINK requires an 'emailLinkOptions.email' argument"); return; } if (!arg.emailLinkOptions.url) { reject("Auth type EMAIL_LINK requires an 'emailLinkOptions.url' argument"); return; } const actionCodeSettings = com.google.firebase.auth.ActionCodeSettings.newBuilder() .setUrl(arg.emailLinkOptions.url) .setHandleCodeInApp(true) .setIOSBundleId(arg.emailLinkOptions.iOS ? arg.emailLinkOptions.iOS.bundleId : Application.android.context.getPackageName()) .setAndroidPackageName(arg.emailLinkOptions.android ? arg.emailLinkOptions.android.packageName : Application.android.context.getPackageName(), arg.emailLinkOptions.android ? arg.emailLinkOptions.android.installApp || false : false, arg.emailLinkOptions.android ? arg.emailLinkOptions.android.minimumVersion || '1' : '1') .build(); const onEmailLinkCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (!task.isSuccessful()) { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } else { firebase.rememberEmailForEmailLinkLogin(arg.emailLinkOptions.email); resolve(); } }, }); firebaseAuth.sendSignInLinkToEmail(arg.emailLinkOptions.email, actionCodeSettings).addOnCompleteListener(onEmailLinkCompleteListener); } else if (arg.type === firebase.LoginType.PHONE) { if (!arg.phoneOptions || !arg.phoneOptions.phoneNumber) { reject("Auth type PHONE requires a 'phoneOptions.phoneNumber' argument"); return; } const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user && firebase._alreadyLinkedToAuthProvider(user, 'phone')) { resolve(toLoginResult(user)); return; } const OnVerificationStateChangedCallbacks = com.google.firebase.auth.PhoneAuthProvider.OnVerificationStateChangedCallbacks.extend({ onVerificationCompleted: (phoneAuthCredential) => { firebase._verifyPhoneNumberInProgress = false; const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (!user || firebase._alreadyLinkedToAuthProvider(user, 'phone')) { firebaseAuth.signInWithCredential(phoneAuthCredential).addOnCompleteListener(onCompleteListener); } else { user.linkWithCredential(phoneAuthCredential).addOnCompleteListener(onCompleteListener); } }, onVerificationFailed: (firebaseException) => { firebase._verifyPhoneNumberInProgress = false; const errorMessage = firebaseException.getMessage(); if (errorMessage.includes('INVALID_APP_CREDENTIAL')) { if (firebase.reject) { firebase.reject('Please upload the SHA1 fingerprint of your debug and release keystores to the Firebase console, see https://github.com/EddyVerbruggen/nativescript-plugin-firebase/blob/master/docs/AUTHENTICATION.md#phone-verification'); } } else { if (firebase.reject) { firebase.reject(errorMessage); } } }, onCodeSent: (verificationId, forceResendingToken) => { setTimeout(() => { if (firebase._verifyPhoneNumberInProgress) { firebase._verifyPhoneNumberInProgress = false; firebase.requestPhoneAuthVerificationCode((userResponse) => { if (userResponse === undefined && firebase.reject) { firebase.reject('Prompt was canceled'); return; } const authCredential = com.google.firebase.auth.PhoneAuthProvider.getCredential(verificationId, userResponse); const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (!user || firebase._alreadyLinkedToAuthProvider(user, 'phone')) { firebaseAuth.signInWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } else { user.linkWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } }, arg.phoneOptions.verificationPrompt); } }, 3000); }, }); firebase._verifyPhoneNumberInProgress = true; let timeout = arg.phoneOptions.android ? arg.phoneOptions.android.timeout : 60; com.google.firebase.auth.PhoneAuthProvider.getInstance().verifyPhoneNumber(arg.phoneOptions.phoneNumber, timeout, java.util.concurrent.TimeUnit.SECONDS, Application.android.foregroundActivity, new OnVerificationStateChangedCallbacks()); } else if (arg.type === firebase.LoginType.CUSTOM) { if (!arg.customOptions || (!arg.customOptions.token && !arg.customOptions.tokenProviderFn)) { reject("Auth type CUSTOM requires a 'customOptions.token' or 'customOptions.tokenProviderFn' argument"); return; } if (arg.customOptions.token) { firebaseAuth.signInWithCustomToken(arg.customOptions.token).addOnCompleteListener(onCompleteListener); } else if (arg.customOptions.tokenProviderFn) { arg.customOptions.tokenProviderFn().then( (token) => { firebaseAuth.signInWithCustomToken(token).addOnCompleteListener(onCompleteListener); }, (error) => { reject(error); } ); } } else if (arg.type === firebase.LoginType.FACEBOOK) { if (typeof com.facebook === 'undefined' || typeof com.facebook.FacebookSdk === 'undefined') { reject('Facebook SDK not installed - see gradle config'); return; } if (!fbCallbackManager) { com.facebook.FacebookSdk.sdkInitialize(Application.getNativeApplication()); fbCallbackManager = com.facebook.CallbackManager.Factory.create(); } const callback = (eventData) => { Application.android.off(AndroidApplication.activityResultEvent, callback); fbCallbackManager.onActivityResult(eventData.requestCode, eventData.resultCode, eventData.intent); }; Application.android.on(AndroidApplication.activityResultEvent, callback); const fbLoginManager = com.facebook.login.LoginManager.getInstance(); fbLoginManager.registerCallback( fbCallbackManager, new com.facebook.FacebookCallback({ onSuccess: (loginResult) => { firebase._facebookAccessToken = loginResult.getAccessToken().getToken(); const authCredential = com.google.firebase.auth.FacebookAuthProvider.getCredential(firebase._facebookAccessToken); const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user) { if (firebase._alreadyLinkedToAuthProvider(user, 'facebook.com')) { firebaseAuth.signInWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } else { user.linkWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } } else { firebaseAuth.signInWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } }, onCancel: () => reject('Facebook Login canceled'), onError: (ex) => reject('Error while trying to login with Fb ' + ex), }) ); let scopes = ['public_profile', 'email']; if (arg.facebookOptions && arg.facebookOptions.scopes) { scopes = arg.facebookOptions.scopes; } const permissions = Utils.android.collections.stringArrayToStringSet(scopes); const activity = Application.android.foregroundActivity; fbLoginManager.logInWithReadPermissions(activity, permissions); } else if (arg.type === firebase.LoginType.APPLE) { const onSuccessListener = new gmsTasks.OnSuccessListener({ onSuccess: (authResult) => { firebase._appleSignInIdToken = authResult.getCredential().getIdToken(); const loginResult = toLoginResult(authResult.getUser(), authResult.getAdditionalUserInfo()); firebase.notifyAuthStateListeners({ loggedIn: true, user: loginResult, }); resolve(loginResult); }, }); const onFailureListener = new gmsTasks.OnFailureListener({ onFailure: (exception) => { reject(exception.getMessage()); }, }); const pendingAuthResult = firebaseAuth.getPendingAuthResult(); if (pendingAuthResult) { pendingAuthResult.addOnSuccessListener(onSuccessListener).addOnFailureListener(onFailureListener); } else { const oAuthProviderBuilder = com.google.firebase.auth.OAuthProvider.newBuilder('apple.com'); let scopes = ['name', 'email']; if (arg.appleOptions && arg.appleOptions.scopes) { scopes = arg.appleOptions.scopes; } oAuthProviderBuilder.setScopes(firebase.toJavaArray(scopes)); if (arg.appleOptions && arg.appleOptions.locale) { oAuthProviderBuilder.addCustomParameter('locale', arg.appleOptions.locale); } const provider = oAuthProviderBuilder.build(); firebaseAuth .startActivityForSignInWithProvider(Application.android.foregroundActivity || Application.android.startActivity, provider) .addOnSuccessListener(onSuccessListener) .addOnFailureListener(onFailureListener); } } else if (arg.type === firebase.LoginType.GOOGLE) { if (typeof com.google.android.gms.auth.api.Auth === 'undefined') { reject('Google Sign In not installed - see gradle config'); return; } const clientStringId = Utils.android.resources.getStringId('default_web_client_id'); const clientId = Utils.android.getApplicationContext().getResources().getString(clientStringId); const googleSignInOptionsBuilder = new com.google.android.gms.auth.api.signin.GoogleSignInOptions.Builder(com.google.android.gms.auth.api.signin.GoogleSignInOptions.DEFAULT_SIGN_IN).requestServerAuthCode(clientId).requestIdToken(clientId).requestEmail(); if (arg.googleOptions && arg.googleOptions.hostedDomain) { googleSignInOptionsBuilder.setHostedDomain(arg.googleOptions.hostedDomain); } if (arg.googleOptions && arg.googleOptions.scopes) { const scopesArray = []; if (arg.googleOptions.scopes.length > 1) { arg.googleOptions.scopes.forEach((s) => scopesArray.push(new com.google.android.gms.common.api.Scope(s))); } googleSignInOptionsBuilder.requestScopes(new com.google.android.gms.common.api.Scope(arg.googleOptions.scopes[0]), scopesArray); } const googleSignInOptions = googleSignInOptionsBuilder.build(); const onConnectionFailedListener = new com.google.android.gms.common.api.GoogleApiClient.OnConnectionFailedListener({ onConnectionFailed: (connectionResult) => { reject(connectionResult.getErrorMessage()); }, }); firebase._mGoogleApiClient = new com.google.android.gms.common.api.GoogleApiClient.Builder(Application.getNativeApplication()).addOnConnectionFailedListener(onConnectionFailedListener).addApi(com.google.android.gms.auth.api.Auth.GOOGLE_SIGN_IN_API, googleSignInOptions).build(); const signInIntent = com.google.android.gms.auth.api.Auth.GoogleSignInApi.getSignInIntent(firebase._mGoogleApiClient); (Application.android.foregroundActivity || Application.android.startActivity).startActivityForResult(signInIntent, GOOGLE_SIGNIN_INTENT_ID); const callback = (eventData) => { if (eventData.requestCode === GOOGLE_SIGNIN_INTENT_ID) { Application.android.off(AndroidApplication.activityResultEvent, callback); const googleSignInResult = com.google.android.gms.auth.api.Auth.GoogleSignInApi.getSignInResultFromIntent(eventData.intent); if (googleSignInResult === null) { reject('No googleSignInResult, eventData.intent seems to be invalid'); return; } const success = googleSignInResult.isSuccess(); if (success) { const googleSignInAccount = googleSignInResult.getSignInAccount(); firebase._googleSignInIdToken = googleSignInAccount.getIdToken(); firebase._googleSignInAuthCode = googleSignInAccount.getServerAuthCode(); const accessToken = null; const authCredential = com.google.firebase.auth.GoogleAuthProvider.getCredential(firebase._googleSignInIdToken, accessToken); firebase._mGoogleApiClient.connect(); const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user) { if (firebase._alreadyLinkedToAuthProvider(user, 'google.com')) { firebaseAuth.signInWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } else { user.linkWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } } else { firebaseAuth.signInWithCredential(authCredential).addOnCompleteListener(onCompleteListener); } } else { console.log("Make sure you've uploaded your SHA1 fingerprint(s) to the Firebase console. Status: " + googleSignInResult.getStatus()); reject('Has the SHA1 fingerprint been uploaded? Sign-in status: ' + googleSignInResult.getStatus()); } } }; Application.android.on(AndroidApplication.activityResultEvent, callback); } else { reject('Unsupported auth type: ' + arg.type); } } catch (ex) { console.log('Error in firebase.login: ' + ex); reject(ex); } }); }; firebase._alreadyLinkedToAuthProvider = (user, providerId) => { const providerData = user.getProviderData(); for (let i = 0; i < providerData.size(); i++) { const profile = providerData.get(i); if (profile.getProviderId() === providerId) { return true; } } return false; }; firebase.reauthenticate = (arg) => { return new Promise((resolve, reject) => { try { const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user === null) { reject('no current user'); return; } firebase.moveLoginOptionsToObjects(arg); let authCredential = null; if (arg.type === firebase.LoginType.PASSWORD) { if (!arg.passwordOptions || !arg.passwordOptions.email || !arg.passwordOptions.password) { reject("Auth type PASSWORD requires an 'passwordOptions.email' and 'passwordOptions.password' argument"); return; } authCredential = com.google.firebase.auth.EmailAuthProvider.getCredential(arg.passwordOptions.email, arg.passwordOptions.password); } else if (arg.type === firebase.LoginType.GOOGLE) { if (!firebase._googleSignInIdToken) { reject('Not currently logged in with Google'); return; } authCredential = com.google.firebase.auth.GoogleAuthProvider.getCredential(firebase._googleSignInIdToken, null); } else if (arg.type === firebase.LoginType.FACEBOOK) { if (!firebase._facebookAccessToken) { reject('Not currently logged in with Facebook'); return; } authCredential = com.google.firebase.auth.FacebookAuthProvider.getCredential(firebase._facebookAccessToken); } if (authCredential === null) { reject('arg.type should be one of LoginType.PASSWORD | LoginType.GOOGLE | LoginType.FACEBOOK'); return; } const onCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (task.isSuccessful()) { const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); const loginResult = toLoginResult(user); firebase.notifyAuthStateListeners({ loggedIn: true, user: loginResult, }); resolve(loginResult); } else { reject(task.getException() && task.getException().getReason ? task.getException().getReason() : task.getException()); } }, }); user.reauthenticate(authCredential).addOnCompleteListener(onCompleteListener); } catch (ex) { console.log('Error in firebase.reauthenticate: ' + ex); reject(ex); } }); }; firebase.reloadUser = () => { return new Promise((resolve, reject) => { try { const user = com.google.firebase.auth.FirebaseAuth.getInstance().getCurrentUser(); if (user === null) { reject('no current user'); return; } const onCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (task.isSuccessful()) { resolve(); } else { reject('Reload failed ' + task.getException()); } }, }); user.reload().addOnCompleteListener(onCompleteListener); } catch (ex) { reject(ex); } }); }; firebase.sendPasswordResetEmail = (email) => { return new Promise((resolve, reject) => { try { const onCompleteListener = new gmsTasks.OnCompleteListener({ onComplete: (task) => { if (task.isS