I implemented a native module which navigates to a camera activity. But while calling the camera from nativeModules, it takes 1500-2000ms to open(excluding ui updation in camera).
The native module class that extends ReactContextBaseJavaModule is written like this:
#ReactModule(name = ImagePickerModule.NAME)
public class ImagePickerModule extends ReactContextBaseJavaModule
implements ActivityEventListener
{
....
// Calling this method
#ReactMethod
public void launchCamera(final ReadableMap options, final Callback callback) {
// this method opens camera after checking necessary permissions and applies UI changes which was set by the user previously
}
....
}
And this is nativeModules to JS mapping in the .ts file
import {NativeModules} from 'react-native';
import {ImagePickerNativeModule} from './privateTypes';
const NativeInterface: ImagePickerNativeModule | undefined =
NativeModules.ImagePickerManager;
const DEFAULT_OPTIONS: ImagePickerOptions = {
// options here
}
class ImagePicker {
launchCamera(options: ImagePickerOptions, callback: Callback): void {
return NativeInterface.launchCamera(
{
...DEFAULT_OPTIONS,
...options,
tintColor: processColor(options.tintColor || DEFAULT_OPTIONS.tintColor),
},
callback,
);
}
}
I am calling the nativeModule from react-native code like this:
export const CustomCamera = (): Promise<{ uri: string }> => {
return new Promise((resolve, reject) => {
ImagePicker.launchCamera(***Camera options passed***)
.then(res => // Do something here)
.catch(err => // Do something here)
}
}
Is there any way I can open the activity faster while calling it from native modules? or keep the activity in the background so that the cameraActivity can load fast while calling it from react-native? Please suggest.
Related
I have a set of functions in a util module. Most of the functions are simple data manipulation, however, one of them makes a REST call. Many modules/classes call this method that makes the REST call for its values. Instead of the app/browser making multiple (>20) of the calls, can i make 1, and save the result. Then return the saved result and refrain from making subsequent calls?
utils.ts
import axios from 'axios'
import { of, from } from 'rxjs';
import { shareReplay, switchMap, first } from 'rxjs/operators';
let cache: Observable<any>; // <-- global cache to set/get
export function makeRequest() {
const promise = axios.get('http:rest-server:1234/user/data');
const obs = from(promise);
return obs.pipe(
map(res => { return of(res) })
catchError(err => { cache })
);
}
export function getUserData() {
if(!cache) { // <-- if cache isnt empty, make the REST call
cache = makeRequest()
.pipe(
shareReplay(2),
first()
)
}
return cache; // <- return the originally populated cache
}
index.ts
import * as Config from './utils';
myComponent.ts
import { Config } from 'my-helper-library';
export class MyComponent {
public init() {
Config.getUserData()
.subscribe(.......
}
}
Note, this singleton will be consumed by both Angular and React apps.
I want to write a plugin that contain all needed services and use this services easily when is needed.
I have wrote a plugin but it doesn't work !!
How to know what is wrong ?
This is plugin i wrote .
export default ({ $axios}:any , inject:any) => {
class BlogService {
getPost() {
return $axios.$get('/posts')
}
delete(id: Number) {
return $axios.Sdelete('/post/' + id)
}
}
inject(new BlogService)
}
And this is error i get
The inject method takes in two parameters. The first parameter is a string and will be the name of the property and then the second argument is the value (in your case, new BlogService()). I would also add the value to the context, so that you can access your service in asyncData and anywhere else the context is available.
Here's a rewritten version of your snippet, with these changes applied:
export default (context, inject) => {
const { $axios } = context
class BlogService {
getPost() {
return $axios.$get('/posts')
}
delete(id) {
return $axios.Sdelete('/post/' + id)
}
}
const blogService = new BlogService()
context.$blogService = blogService // Adds $blogService to the context.
inject('blogService', blogService) // Adds $blogService to all of your components.
}
While you haven't tagged your post with TypeScript, it looks as if you're using TypeScript in your original snippet, so I've also rewritten the snippet for TypeScript as you'll need to extend the default types with your new injected property. This is just to stop your linter from going crazy and your code completion to work.
import { Context, Plugin } from '#nuxt/types'
class BlogService {
readonly context: Context
constructor (context: Context) {
this.context = context
}
getPost() {
return this.context.$axios.$get('/posts')
}
delete(id: number) {
return this.context.$axios.Sdelete('/post/' + id)
}
}
// Create a new interface so that you don't have to add the new properties to all of the existing types every time.
interface Services {
$blogService: BlogService
}
declare module 'vue/types/vue' {
interface Vue extends Services {
}
}
declare module '#nuxt/types' {
interface NuxtAppOptions extends Services {
}
interface Context extends Services {
}
}
const servicesPlugin: Plugin = (context, inject) => {
const { $axios } = context
const blogService = new BlogService(context)
context.$blogService = blogService // Adds $blogService to the context.
inject('blogService', blogService) // Adds $blogService to all of your components.
}
export default servicesPlugin
i used above code and there is some error here .#tarkan
I've been out of work for a while, and a friend who owns a startup company tasked me with fixing the Facebook Login functionality of his app. Big opportunity for me.
None of the devs who built/worked on it are around anymore, and the app's code is written in such a confusing way. So I'm bringing it here in hopes that I can get help to resolve it.
The Issue
When you open the app there's an intro screen, you close that, and then it prompts you to login with Facebook.
When Login is clicked, it loads for a bit, and then just returns back to the initial intro screen.
The debugger console displays:
[CodePush] Reporting binary update (2.0.0)
[CodePush] Report status failed: {"appVersion":"2.0.0"}
Not really familiar with CodePush, and I've been investigating that on and off, unsure if that's even related to my issue or not. I went through their docs and made sure this project was configured right anyway.
Then I did the same with Facebook SDK. I checked the docs and compared the instructions to what was done in the app, to see if the previous devs configured it properly. Everything looks right.
Docs I'm referring to:
https://developers.facebook.com/docs/facebook-login/android/v2.2
NOTE I can't do steps 5 and beyond, because you need to log in to complete those, and my FB account is not connected to the app. Currently waiting to hear back from someone who worked on this. Likely not relevant anyway, as everything else was done correctly.
I found the code for the Login Button in the codebase, but there's a lot of files importing to each other, and I'm not sure what exactly does what. I will post the bread trail I followed below.
Here I track the Login button to find the source of the implemented feature.
I skip files that are unnecessary, such as the screen that displays the greeting along with the Login button. I followed the import statements until I reached the following:
LoginButtonContainer.js
// #flow
import { connect } from 'react-redux'
import { loginWithFbButtonPressed } from '../redux/actions'
import LoginWithFbButton, {
Props as LoginButtonComponentProps,
} from '../components/LoginWithFbButton' // <<<~~~ This file confused me, so next I checked here
type LoginButtonProps = {
onPress: any => void,
}
const mapDispatchToProps = (dispatch: any) => ({
login: () => dispatch(loginWithFbButtonPressed()),
})
const mergeProps = (
_,
dispatchProps: { login: () => void },
ownProps: LoginButtonProps
): LoginButtonComponentProps => {
const { login } = dispatchProps
const { onPress = () => null } = ownProps
return {
onPress: () => {
onPress()
login()
},
}
}
export default connect(null, mapDispatchToProps, mergeProps)(LoginWithFbButton)
LoginWithFbButton.js
// #flow
import * as React from 'react'
import { View, Text, Dimensions, StyleSheet } from 'react-native'
import Icon from 'react-native-vector-icons/FontAwesome'
import Entypo from 'react-native-vector-icons/Entypo'
import { heavyGray, lightGray, facebookColor } from '../constants/colors'
export type Props = {
onPress: () => void,
advisoryText: string,
}
/**
* #class LoginWithFbButton
* Facebook compliant component to login with FB, do not use any other medium to login with FB as to not break the TOS
*/
class LoginWithFbButton extends React.PureComponent<Props> {
render() {
const {
onPress,
advisoryText = `We don't post anything to Facebook`,
} = this.props
return (
<View style={styles.container}>
<Icon.Button
name="facebook"
backgroundColor={facebookColor}
onPress={onPress}
style={styles.facebookButton}
>
Login with Facebook
</Icon.Button>
<View style={styles.advisoryContainer}>
<Entypo
color={heavyGray}
name="info-with-circle"
style={styles.infoIcon}
/>
<Text style={styles.advisoryText}>{advisoryText}</Text>
</View>
</View>
)
}
}
export default LoginWithFbButton
This led me to search for <LoginWithFBButton> but I do not see that anywhere in the app.
Despite me not finding that tag anywhere, the Login button is displayed on the screen.
Lastly(maybe) there's a file called facebook.js
facebook.js
// #flow
import FBSDK from 'react-native-fbsdk';
const { LoginManager, AccessToken } = FBSDK;
export type OpenFBLoginResult =
| {
fbData: string,
}
| {
error: any,
};
export type FacebookDataState = {
accessToken: string,
applicationID: string,
declinedPermissions: Array<string>,
expirationTime: number,
lastRefreshTime: number,
permissions: Array<string>,
userID: string,
};
const getToken = (): Promise<?string> =>
AccessToken.getCurrentAccessToken().then(t => (t ? t.accessToken : null));
const openFBLogin = (): Promise<OpenFBLoginResult> =>
LoginManager.logInWithReadPermissions([
'public_profile',
'email',
]).then(result => {
if (result.isCancelled) {
return {
error: 'User cancelled Facebook login',
};
}
return AccessToken.getCurrentAccessToken().then(fbData => ({
...result,
fbData,
}));
});
const logOut = (): Promise<void> => LoginManager.logOut();
/**
* Dummies
*/
class GraphRequest {}
const GraphRequestManager = () => ({
addRequest: () => ({
start: () => null,
}),
});
const fetchUserImage = (facebookId: string) => {
return new Promise((resolve, reject) => {
const path = `/${facebookId}/picture`;
// Create a graph request asking for user information with a callback to handle the response.
const infoRequest = new GraphRequest(
path,
null,
(error: ?Object, result: ?Object) => {
if (error) {
reject(error);
} else {
resolve(result);
}
}
);
// Start the graph request.
new GraphRequestManager().addRequest(infoRequest).start();
});
};
export default {
openFBLogin,
getToken,
logOut,
fetchUserImage,
};
// export function* openFBLogin(): OpenFBLoginResult {
// type openFBLoginResultType = { +type: string, +token: string }
// const response: openFBLoginResultType = yield call(Expo.Facebook.logInWithReadPermissionsAsync, FBAPP_ID, {
// permissions: FB_PERMISSIONS
// })
// let error: ?any = null
// switch (response.type) {
// case 'success':
// const { token } = response
// yield call(_setFBToken, token)
// yield put(actions.loginFb.success('', token))
// return { token }
// case 'cancel':
// error = CANCELLED_ERROR
// yield put(actions.loginFb.failure('', error))
// return { error }
// default:
// error = JSON.stringify(response)
// yield put(actions.loginFb.failure('', error))
// return { error }
// }
// }
This is probably not a great post, but a lot rides on this, and I'm hoping something obvious sticks out to someone more experienced than I.
If I've left anything out, I will update this post with whatever I can. Thanks all.
I am making a video chat app which has to work in a webview of my android application.
So What I want is to set audio and video to true or false depending on java. it means if I clicked to audio call button in ui button I should set video to false and vice versa.
this.getUserMedia = navigator.mediaDevices.getUserMedia({
audio: true,
video: true
})
Here is the full code for the Component containing the above lines.
import React, { Component } from 'react';
import MediaContainer from './MediaContainer'
import CommunicationContainer from './CommunicationContainer'
import { connect } from 'react-redux'
import store from '../store'
import io from 'socket.io-client'
class RoomPage extends Component {
constructor(props) {
super(props);
this.getUserMedia = navigator.mediaDevices.getUserMedia({
audio: true,
video: true
}).catch(e => alert('getUserMedia() error: ' + e.name))
this.socket = io.connect();
}
componentDidMount() {
this.props.addRoom();
}
render(){
return (
<div>
<MediaContainer media={media => this.media = media} socket={this.socket} getUserMedia={this.getUserMedia} />
<CommunicationContainer socket={this.socket} media={this.media} getUserMedia={this.getUserMedia} />
</div>
);
}
}
const mapStateToProps = store => ({rooms: new Set([...store.rooms])});
const mapDispatchToProps = (dispatch, ownProps) => (
{
addRoom: () => store.dispatch({ type: 'ADD_ROOM', room: ownProps.match.params.room })
}
);
export default connect(mapStateToProps, mapDispatchToProps)(RoomPage);
If you can provide me with a sample code please. I am new in React, so please be as explicit as possible.
You can use javascript to call a native function.
In android (java) , Create a class which will be used as JavascriptInterface
public class MyExecutorInterface {
Context mctxt;
MyExecutorInterface (Context c) {
mctxt= c;
}
#JavascriptInterface // must be added for API 17 or higher
public void executeAction(String message) {
Toast.makeText(mctxt, message, Toast.LENGTH_SHORT).show();
}
}
When you declare your webview, enable javascript and pass the class in charge to execute action.
MyExecutorInterface jsInt = new MyExecutorInterface(this);
webView.getSettings().setJavaScriptEnabled(true);
webView.addJavascriptInterface(jsInt, "JSInterface"); // JSInterface is what will be used in javascript
Now you can call your action in Javascript like this:
window.JSInterface.executeAction(message)
I'm working on a background page in a Chrome extension that dispatches a Redux action asynchronously with Thunk. The action creator is defined like the following:
export const executeProcess = (data: Data[]): ThunkAction<Promise<void>, {}, {}, AnyAction> => async (dispatch: ThunkDispatch<{}, {}, AnyAction>): Promise<void> => {
I'm able to dispatch this perfectly fine from a screen using the component's map dispatch to props, that is:
const mapDispatchToProps = {
executeProcess: executeProcess,
};
And:
eventTest = async () => {
//
// Kickoff process
await this.props.executeProcess(this.props.data);
};
And the JSX itself:
<button onClick={this.eventTest}>EVENT TESTER</button>
I'm trying to do something similar in the background page, notably:
chrome.alarms.onAlarm.addListener(async () => {
await store.dispatch(executeProcess(store.getState().data))
});
And doing so invokes the following TS error:
Property 'type' is missing in type 'ThunkAction<Promise<void>, {}, {}, AnyAction>' but required in type 'AnyAction'.
I'm using the webext-redux NPM package so that I'm able to work with the store in both the screens and background pages and am able to read from the store in the background page, however can't dispatch actions. The dispatch definition requires an instance of type AnyAction, that is:
export interface AnyAction extends Action
However the ThunkAction naturally extends from Action:
export type ThunkAction<R, S, E, A extends Action> = (
Is there any way I can change the signature of the action creator so that the dispatch works without issues in both the screens and also the background page?
How I'm declaring my store.ts using the (aforementioned NPM) is the following:
const createStoreWithMiddleware = applyMiddleware(reduxThunk)(createStore);
let store: Store<RootState>;
store = createStoreWithMiddleware(reducers, loadState());
store.subscribe(throttle(() => {
saveState(store.getState())
}, 1000));
wrapStore(store, {
portName: constants.ApplicationName,
});
export {store};
A solution/kludge to make this work, define the store like the following:
let store: Store<RootState, any>;
which resolves to the following:
export interface Store<S = any, A extends Action = AnyAction> {
instead of this:
let store: Store<RootState>;
Ideally would pass ThunkAction instead of any type, but ran into generic argument issue.