Simple way to get the bundle identifier at runtime in React Native? - react-native

We've hit a problem that could be solved if we know the bundle identifier at run time in our RN app. We've seen a few libraries but would rather not include a whole library to do this one thing. Is there a simple way to get this information in the code?
Thanx

on mac you can see it inside general Tab
you can also use
import DeviceInfo from "react-native-device-info";
console.log("# device ",DeviceInfo.getBundleId())

It seems like libraries like react-native-device-info use native iOS and Android code in order to return the applications bundle identifier which means that react-native doesn't provide that in javascript. You could use React Native's native-modules API to send the bundle id from Java or Objective C to javascript (they have a section in the linked docs on how to export constant values).
Also here are some snippets from react-native-device-info on how they retrieved the bundle identifier.
On Android (RNDeviceModule.java):
String bundleId = this.reactContext.getPackageName();
On iOS (RNDeviceInfo.m) - keep in mind idk objective-c so this snippet might not work:
[[NSBundle mainBundle] objectForInfoDictionaryKey:#"CFBundleIdentifier"] ?: [NSNull null]
Also if you are using expo currently, then you can access the app.json file with Expo.Constants:
import { Constants } from 'expo';
// this will only work if you specify the bundleIdentifier in app.json
let bundleId = Constants.manifest.ios.bundleIdentifier;
Hope this mess of a post somewhat helps! Honestly, it might just be worth it to use a library but it's up to you.

You can get this from DeviceInfo.getVersion()
replace getVersion to the following list according to your need
export function getUniqueID(): string;
export function getManufacturer(): string;
export function getDeviceId(): string;
export function getSystemName(): string;
export function getSystemVersion(): string;
export function getBundleId(): string;
export function getBuildNumber(): string;
export function getVersion(): string;
export function getDeviceName(): string;

If you are using react-native-fs in your app anyway, you can do the following slightly ugly hack to get your bundle Id:
import RNFS from 'react-native-fs';
getAppBundleIdAndroid = () =>
RNFS.DocumentDirectoryPath.replace(/.+\/(.+?)\/files/, '$1');
}

Related

React Native dependency import memory consumption: import all illustrations vs import specific illustration from package

If a Component of a React Native application is doing the following:
import * as Illustrations from '#xyz/illustrations';
and using it like:
function App() {
// Method to get an actual ReactElement out of the illustrations
const getIllustration = (illu: string): ReactElement => {
const Illu = (Illustrations as { [key: string]: any })[illu];
return <Illu />;
};
return {getIllustration(illustration)};
}
vs:
import { Myillustration} from '#xyz/illustrations';
function App() {
return <Myillustration />;
}
then what effect does it have on the memory consumption of an Android App builded with React Native? I thought, that importing all illustration by import * as Illustrations from '#xyz/illustrations'; and then just extracting one specific Illustration is a huge memory consumption problem, but my tests with the Android Device Monitor shows me that both methods do not make any difference in memory consumption. The same is valid for the APK size created for both ways. They are identical.
Questions:
Is the bundle loaded completely on app start into the memory (RAM) from the application? As far as I know a ReactNative application runs in one Activity and the screens should be Fragments and therefore it might load everything into RAM, but I might be wrong as I don't find any information regarding that topic.
Why does importing all illustrations out of one package does not increase the memory consumption, like described?
Is there a way to analyze the memory consumption of a specific React Native screen?
UPDATE:
Ok, now I know, that it makes no difference for React Native if I import a Component/Illustration like:
import * as Illustrations from '#xyz/illustrations';
or
import { Myillustration } from '#xyz/illustrations';
because Tree Shaking is not supported and therefore the transpiled Code (into Javascript) looks for both like (I use TypesScript directly via yarn buid:ts and see the output in the /dist folder):
const illustrations_1 = require("#xyz/illustrations");
...
react_1.default.createElement(illustrations_1.Myillustration, null))),

import pdfjslib into vuejs component

I would like to create a viewer PDF files into electron/vuejs application.
I need to use the pdfjs librarie.
For that I installed this package : "pdfjs-dist": "2.6.347"
and in my component vuejs I try to used this by doing this :
import pdfjsLib from "pdfjs-dist/webpack";
This import instruction seeems to be running good. But If a start used this like this :
created()
{
pdfjsLib.getDocument()
}
I throw this error :
Cannot read property 'getDocument' of undefined"
I try lot of tricks but I don't find any solution for use this library in my component.
Anyone have a vuejs project with pdfjslib for viewing pdf ?
This seems to work:
import("pdfjs-dist").then((pdfjsLib) => {
pdfjsLib.getDocument();
});
It can be used inside either created() or mounted(). I'd personally use it in mounted.
Working demo here.
Also note calling getDocument() with no arguments seems to trigger some lib error (but that's outside the scope of current question):
Invalid parameter in getDocument, need either Uint8Array, string or a parameter object

how to access xml static resource in react native

I want to add a static xml asset to my react native project and access it just like accessing images.
I added
resolver: {
assetExts: ['png', 'xml'],
},
to metro.config.js and const asset = require('asset.xml') returns me a number. But how to get the file content from this number?
Below code gets me a URI in development mode that I can use axios to fetch it, but in release mode it only returns a filename like asset, how to read it in release mode?
Image.resolveAssetSource(asset).uri;
You can use expo-asset to get the localUri:
const [{ localUri }] = await Asset.loadAsync(require('path/to/your/asset.xml'))
Then you can use expo-file-system to get the contents of the file as string:
const xmlString = FileSystem.readAsStringAsync(localUri)
Then you can convert the xml string to a JS object with a package like fast-xml-parser.
In order for this to work, you should edit your metro.config.js just as you mentioned above, namely: assetExts array should contain xml.
Also, if you use Typescript, you should add a declaration file, like xml.d.ts with the content of:
declare module '*.xml' {
const moduleId: number; // the react-native import reference
export default moduleId;
}
and that declaration file should be in a folder, that's added to typeRoots property in tsconfig.json.
Just a quick reminder: you can use this solution without Expo in a bare react-native app, you just have to install unimodules, which is described in the above links.
Good luck! :)

Redux: Is there any smart way to avoid the antipattern of importing store for helper files?

I'm currently build a React Native application using Redux the state management and Firebase Cloud Messaging for my real time communication.
To use FCM in the background on Android you are required to create file called bgMessaging.js.
// #flow
import firebase from 'react-native-firebase';
// Optional flow type
import type { RemoteMessage } from 'react-native-firebase';
export default async (message: RemoteMessage) => {
// handle your message
return Promise.resolve();
}
My problem is that I need to dispatch an action here. The only solution I found for this was to import my store and call store.dispatch(). I've been told this is an anti-pattern and considered bad practice. What else could I do that is not an anti-pattern?
Edit:
Mark Erikson himself was so kind and gave his opinion on this topic. Thanks Mark!
I've also come into the same scenario when writing my application. My approach to my React Native App was to create React Components, but deal with a lot of my data fetching/handling outside of React Components - because I didn't know whether I'd be using React all of the time, but wanted to create re-usable modules for my other Type/JavaScript projects. For example I'd created a few helper files which dealt with various APIs, but when I integrated Redux into my project - I had the same issue. How do I dispatch without re-adding in your store (as I can see this can be considered Anti-Pattern).
Reading into a few articles, there's no real place to suggest that this approach is 'Anti Pattern'. A lot of the time, stores are imported within the React Context (which is doesn't need to be) - this is Anti Pattern. In your use case, I don't really see how that can be Anti Pattern, I certainly came to this conclusion when I was doing the same thing. In my view 'Common' parts of the app should be used by many other parts of the application.
What I'm seeing is that you need to provide a function which has a single arg, typed as RemoteMessage which returns a promise, and you need to provide that function to registerHeadlessTask (wrapped in another function for some reason..)
So what if your bgMessaging file looked like this..
// #flow
import firebase from 'react-native-firebase';
// Optional flow type
import type { RemoteMessage } from 'react-native-firebase';
export default store => {
return async (message: RemoteMessage) => {
// handle your message
store.dispatch();
return Promise.resolve();
}
}
and in your index you did..
import bgMessaging from './src/bgMessaging';
const store = redux.createStore();
const bgMessagingFn = bgMessaging(store);
// Current main application
AppRegistry.registerComponent('ReactNativeFirebaseDemo', () => bootstrap);
// New task registration
AppRegistry.registerHeadlessTask('RNFirebaseBackgroundMessage', () => bgMessagingFn);

Correct way to use initialize firestore in react-native expo app

Have seen two different ways to initialize firestore in a react-native app and would like to know what the differences between the two are. The method shown in the firestore docs (https://firebase.google.com/docs/firestore/quickstart#initialize) looks like
const admin = require('firebase-admin');
const functions = require('firebase-functions');
admin.initializeApp(functions.config().firebase);
export fs = admin.firestore();
while the "firebase" way (as seen in this expo post: https://forums.expo.io/t/open-when-an-expo-firebase-firestore-platform/4126/29), which is the way I currently use and appears to work, looks like
import * as firebase from 'firebase';
import 'firebase/firestore';//for using firestore functions, see https://stackoverflow.com/a/50684682/8236733
import { firebaseConfig } from './firebase-credentials';//WARN: gitignored, exports object containing firebase (web)app credentials
// Initialize Firebase
// why in separate file? see https://github.com/zeit/next.js/issues/1999 and https://ilikekillnerds.com/2018/02/solving-issue-firebase-app-named-default-already-exists/
// firebase.initializeApp(firebaseConfig);
try {
firebase.initializeApp(firebaseConfig)
/*WARN:
#firebase/firestore:, Firestore (5.0.4):
The behavior for Date objects stored in Firestore is going to change
AND YOUR APP MAY BREAK.
To hide this warning and ensure your app does not break, you need to add the
following code to your app before calling any other Cloud Firestore methods:
const firestore = firebase.firestore();
const settings = {timestampsInSnapshots: true};
firestore.settings(settings);
With this change, timestamps stored in Cloud Firestore will be read back as
Firebase Timestamp objects instead of as system Date objects. So you will also
need to update code expecting a Date to instead expect a Timestamp. For example:
// Old:
const date = snapshot.get('created_at');
// New:
const timestamp = snapshot.get('created_at');
const date = timestamp.toDate();
Please audit all existing usages of Date when you enable the new behavior. In a
future release, the behavior will change to the new behavior, so if you do not
follow these steps, YOUR APP MAY BREAK.
*/
const fsSettings = {/* your settings... */ timestampsInSnapshots: true};
firebase.firestore().settings(fsSettings)
} catch (err) {
// we skip the "already exists" message which is
// not an actual error when we're hot-reloading
if (!/already exists/.test(err.message)) {
console.error('Firebase initialization error', err.stack)
}
}
export const fs = firebase.firestore()
The post linked to is the only instance where I could find someone else doing this, but again it does work for me (can read and write to firestore).
Very new to using firebase/firestore and would like to use the more 'correct' method. Is there any difference between initializing firestore in the app in these separate ways?
Import:
import * as firebase from 'firebase';
import 'firebase/firestore';
Then
const db = firebase.firestore();
https://github.com/invertase/react-native-firebase
This is a JavaScript bridge to the native Firebase SDKs for both iOS and Android therefore Firebase will run on the native thread.
It has a step-by-step instructions for react-native app integration with firebase.
One important thing is that you have to consider about your react-native version and firebase sdk version.
They do the same things though? The first one simply does it by declaring and expo does it by declaring it inline. You can do it however you like, but both of them do the same things