I am using react native expo bare workflow
When I open the app on expo client I am able to see the device token on screen but when I convert it to apk
by using
expo build:android
It doesn't show token.
This is my code.
import React, { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import * as Notifications from "expo-notifications";
import * as Permissions from "expo-permissions";
import { TextInput } from "react-native";
export default function App() {
const [token, setToken] = useState("");
const [value, onChangeText] = React.useState("Useless Placeholder");
useEffect(() => {
getPushNotificationPermissions();
});
getPushNotificationPermissions = async () => {
const { status: existingStatus } = await Permissions.getAsync(
Permissions.NOTIFICATIONS,
);
let finalStatus = existingStatus;
// only ask if permissions have not already been determined, because
// iOS won't necessarily prompt the user a second time.
if (existingStatus !== "granted") {
// Android remote notification permissions are granted during the app
// install, so this will only ask on iOS
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
// Stop here if the user did not grant permissions
if (finalStatus !== "granted") {
return;
}
console.log(finalStatus);
// Get the token that uniquely identifies this device
console.log(
"Notification Token: ",
(await Notifications.getExpoPushTokenAsync()).data,
);
setToken((await Notifications.getExpoPushTokenAsync()).data);
};
return (
<View style={styles.container}>
<Text>{token}</Text>
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
alignItems: "center",
justifyContent: "center",
},
});
And also i don't get a push notification on apk but it works on expo client.
Since you're using bare workflow, You should pass your experienceId in an object to getExpoPushTokenAsync, the value of your experienceId is #your-username/your-project-slug
Related
Is there a chance to get an RNChat example which runs on latest expo react native for supporting the great expo plugins like expo av player or expo haptics?
Edit:
Build fails
=== BUILD TARGET React-Codegen OF PROJECT Pods WITH CONFIGURATION Debug ===
Check dependencies
** BUILD FAILED **
The following build commands failed:
CompileSwiftSources normal x86_64 com.apple.xcode.tools.swift.compiler
CompileSwift normal x86_64
(2 failures)
I get tons of errors using the expo and expo-modules-core like:
expo-modules-core/ Class Components Factories swift:71:52: error: unknown attribute '_implicitSelfCapture'
OR
expo-modules-core/ios/Swift/DynamicTypes/DynamicEnumType.swift:7:22: error: expected declaration
let innerType: any Enumerable.Type
Unfortunately, we don't have the chat app example for Expo. Errors you've provided aren't related to ConnectyCube's services.
You can make chat app using our ConnectyCube SDK. The SDK supports Expo except WebRTC (video/audio calls).
See docs how to use ConnectyCube's API and chat for React Native here
Try simple code how to use ConnectyCube SDK with Expo:
npx create-expo-app ExpoConnectyCube
cd ExpoConnectyCube
yarn add react-native-connectycube
yarn ios
import { StatusBar } from "expo-status-bar";
import { useEffect, useState } from "react";
import { StyleSheet, Text, View } from "react-native";
import ConnectyCube from "react-native-connectycube";
const creds = {
appId: 385,
authKey: "DFBMs5-dKBBCXcd",
authSecret: "SkCW-ThdnmRg9Za",
};
const conf = {
debug: { mode: 1 },
};
const user = {
id: 72780,
login: "videouser1",
password: "videouser1",
};
export default function App() {
const [session, setSession] = useState("empty");
const [chat, setChat] = useState(false);
const [message, setMessage] = useState("");
const initConnectyCube = () => {
ConnectyCube.init(creds, conf);
};
const createAuthSession = () => {
ConnectyCube.createSession({ login: user.login, password: user.password })
.then((result) => {
setSession(result);
})
.catch((sessionError) => setChat(sessionError));
};
const chatConnect = () => {
ConnectyCube.chat.onMessageListener = (user, message) => {
setMessage({ user, message });
};
ConnectyCube.chat
.connect({ userId: user.id, password: user.password })
.then(() => {
setChat(true);
ConnectyCube.chat.send(user.id, { body: "Hello", type: "chat" });
})
.catch((chatError) => setChat(chatError));
};
useEffect(() => {
initConnectyCube();
createAuthSession();
chatConnect();
}, []);
return (
<View style={styles.container}>
<Text>{`Session: ${JSON.stringify(session)} \n`}</Text>
<Text>{`Chat connected: ${chat} \n`}</Text>
<Text>{`onMessage: ${JSON.stringify(message)} \n`}</Text>
<StatusBar style="auto" />
</View>
);
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: "#fff",
justifyContent: "center",
},
});
I'm trying to build on the example app provided by livekit, so far I've implemented everything like the example app and I've been successful with connecting to a room on example website, I recieve audio from website, but I don't read the video stream, and I also can't send audio or video at all.
Steps to reproduce the behavior:
add the following to index.js
import { registerRootComponent } from "expo";
import { registerGlobals } from "livekit-react-native";
import App from "./App";
registerRootComponent(App);
registerGlobals();
Rendering the following component in App.tsx
import { Participant, Room, Track } from "livekit-client";
import {
useRoom,
useParticipant,
AudioSession,
VideoView,
} from "livekit-react-native";
import { useEffect, useState } from "react";
import { Text, ListRenderItem, StyleSheet, FlatList, View } from "react-native";
import { ParticipantView } from "./ParticipantView";
import { RoomControls } from "./RoomControls";
import type { TrackPublication } from "livekit-client";
const App = () => {
// Create a room state
const [, setIsConnected] = useState(false);
const [room] = useState(
() =>
new Room({
publishDefaults: { simulcast: false },
adaptiveStream: true,
})
);
// Get the participants from the room
const { participants } = useRoom(room);
const url = "[hard-coded-url]";
const token =
"[hard-coded-token";
useEffect(() => {
let connect = async () => {
// If you wish to configure audio, uncomment the following:
await AudioSession.configureAudio({
android: {
preferredOutputList: ["speaker"],
},
ios: {
defaultOutput: "speaker",
},
});
await AudioSession.startAudioSession();
await room.connect(url, token, {});
await room.localParticipant.setCameraEnabled(true);
await room.localParticipant.setMicrophoneEnabled(true);
await room.localParticipant.enableCameraAndMicrophone();
console.log("connected to ", url);
setIsConnected(true);
};
connect();
return () => {
room.disconnect();
AudioSession.stopAudioSession();
};
}, [url, token, room]);
// Setup views.
const stageView = participants.length > 0 && (
<ParticipantView participant={participants[0]} style={styles.stage} />
);
const renderParticipant: ListRenderItem<Participant> = ({ item }) => {
return (
<ParticipantView participant={item} style={styles.otherParticipantView} />
);
};
const otherParticipantsView = participants.length > 0 && (
<FlatList
data={participants}
renderItem={renderParticipant}
keyExtractor={(item) => item.sid}
horizontal={true}
style={styles.otherParticipantsList}
/>
);
const { cameraPublication, microphonePublication } = useParticipant(
room.localParticipant
);
return (
<View style={styles.container}>
{stageView}
{otherParticipantsView}
<RoomControls
micEnabled={isTrackEnabled(microphonePublication)}
setMicEnabled={(enabled: boolean) => {
room.localParticipant.setMicrophoneEnabled(enabled);
}}
cameraEnabled={isTrackEnabled(cameraPublication)}
setCameraEnabled={(enabled: boolean) => {
room.localParticipant.setCameraEnabled(enabled);
}}
onDisconnectClick={() => {
// navigation.pop();
console.log("disconnected");
}}
/>
</View>
);
};
function isTrackEnabled(pub?: TrackPublication): boolean {
return !(pub?.isMuted ?? true);
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: "center",
justifyContent: "center",
},
stage: {
flex: 1,
width: "100%",
},
otherParticipantsList: {
width: "100%",
height: 150,
flexGrow: 0,
},
otherParticipantView: {
width: 150,
height: 150,
},
});
export default App;
the components used here are mostly the same as what's in the example, I've removed the screensharing logic and the messages
5. I run the app using an expo development build
6. it will log that it's connected, you'll be able to hear sound from the remote participant, but not see any video or send any sound.
7. if i try to add
await room.localParticipant.enableCameraAndMicrophone();
in the useEffect, I get the following error:
Possible Unhandled Promise Rejection (id: 0):
Error: Not implemented.
getSettings#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:103733:24
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:120307:109
generatorResume#[native code]
asyncGeneratorStep#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21908:26
_next#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21927:29
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21932:14
tryCallTwo#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26656:9
doResolve#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26788:25
Promise#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26675:14
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21924:25
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:120173:52
generatorResume#[native code]
asyncGeneratorStep#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21908:26
_next#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21927:29
tryCallOne#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26648:16
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:26729:27
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27687:26
_callTimer#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27602:17
_callReactNativeMicrotasksPass#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27635:17
callReactNativeMicrotasks#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:27799:44
__callReactNativeMicrotasks#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:21006:46
#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20806:45
__guard#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20986:15
flushedQueue#http://192.168.1.150:8081/index.bundle?platform=ios&dev=true&hot=false:20805:21
flushedQueue#[native code]
Expected behavior
This should both receive & send video and audio streams between the two clients
I'm still a newbie to React Native, but I am trying to integrate push notifications to my iOS & Android devices. Most tutorials I have seen with Expo use their website to push a notification using a specific token, but i do not want to do that. I want to send one notification to multiple devices at once (regardless of the OS on the device, aka iOS or Android). I think my best bet is doing it through Firebase, which is what this tutorial does. I also found the GitHub that matches the tutorial, but they use ListView, which is now deprecated. I am getting the error that I cannot use ListView in that Github's code, and when I tried to switch it to a Flatlist, I'm getting an error saying that cloneWithRows is not a function. Can someone help me with that portion of the code? Or if you have alternative resources about how to push a notification to multiple devices let me know please. Edit: I'll post the code below for convenience from the GitHub. All credits go to him. TLDR: Code doesn't work because ListView has been deprecated, and if I change it to FlatList, the cloneWithRows doesn't work. Not sure how to restructure it with a Flatlist, please help if you can.
import React from 'react';
import { StyleSheet, Text, View, StatusBar} from 'react-native';
import { Container, Content, Header, Form, Input, Item, Button, Label, Icon, List } from 'native-base'
import firebase from 'firebase';
import { Permissions, Notifications } from 'expo';
import { FlatList } from 'react-native';
import { ListView } from 'react-native';
var data = []
export default class App extends React.Component {
static navigationOptions = {
header: null
}
constructor(props) {
super(props);
this.ds = new ListView({ rowHasChanged: (r1, r2) => r1 !== r2 })
this.state = {
listViewData: data,
newContact: "",
currentUser: ""
}
}
componentDidMount() {
var currentUser
var that = this
listener = firebase.auth().onAuthStateChanged(function (user) {
if (user != null) {
currentUser = user
that.registerForPushNotificationsAsync(currentUser)
}
listener();
});
firebase.database().ref('/contacts').on('child_added', function (data) {
var newData = [...that.state.listViewData]
newData.push(data)
that.setState({ listViewData: newData })
})
}
loadSubscribers = () => {
var messages = []
//return the main promise
return firebase.database().ref('/subscribers').once('value').then(function (snapshot) {
snapshot.forEach(function (childSnapshot) {
var childKey = childSnapshot.key;
messages.push({
"to": childKey,
"sound": "default",
"body": "New Note Added"
});
});
//firebase.database then() respved a single promise that resolves
//once all the messages have been resolved
return Promise.all(messages)
}).catch(error => {
console.log(error)
})
}
registerForPushNotificationsAsync = async (currentUser) => {
const { existingStatus } = await Permissions.getAsync(Permissions.NOTIFICATIONS);
let finalStatus = existingStatus;
// only ask if permissions have not already been determined, because
// iOS won't necessarily prompt the user a second time.
if (existingStatus !== 'granted') {
// Android remote notification permissions are granted during the app
// install, so this will only ask on iOS
const { status } = await Permissions.askAsync(Permissions.NOTIFICATIONS);
finalStatus = status;
}
// Stop here if the user did not grant permissions
if (finalStatus !== 'granted') {
return;
}
// Get the token that uniquely identifies this device
let token = await Notifications.getExpoPushTokenAsync();
// POST the token to our backend so we can use it to send pushes from there
var updates = {}
updates['/expoToken'] = token
await firebase.database().ref('/users/' + currentUser.uid).update(updates)
//call the push notification
}
addRow(data) {
var key = firebase.database().ref('/contacts').push().key
firebase.database().ref('/contacts').child(key).set({ name: data })
}
async deleteRow(secId, rowId, rowMap, data) {
await firebase.database().ref('contacts/' + data.key).set(null)
rowMap[`${secId}${rowId}`].props.closeRow();
var newData = [...this.state.listViewData];
newData.splice(rowId, 1)
this.setState({ listViewData: newData });
}
render() {
return (
<Container style={styles.container} >
<Header style={{ marginTop: StatusBar.currentHeight }}>
<Content>
<Item>
<Input
onChangeText={(newContact) => this.setState({ newContact })}
placeholder="Add Note"
/>
<Button onPress={() => this.addRow(this.state.newContact)}>
<Icon name="add" />
</Button>
</Item>
</Content>
</Header>
<Content>
<List
enableEmptySections
dataSource={this.ds.cloneWithRows(this.state.listViewData)}
renderRow={data =>
<ListItem>
<Text> {data.val().name}</Text>
</ListItem>
}
renderLeftHiddenRow={data =>
<Button full onPress={() => this.addRow(data)} >
<Icon name="information-circle" />
</Button>
}
renderRightHiddenRow={(data, secId, rowId, rowMap) =>
<Button full danger onPress={() => this.deleteRow(secId, rowId, rowMap, data)}>
<Icon name="trash" />
</Button>
}
leftOpenValue={-75}
rightOpenValue={-75}
/>
</Content>
</Container>
);
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#fff',
},
});
I just started exploring AWS amplify as a backend for my react native application. Being a true beginner on using the service, I want my app to remember the logged in user every time I refresh the emulator.
I know from AWS amplify documentation that I can use the Auth function currentAuthenticatedUser for this purpose, but I have no idea on how to implement a code that does this purpose.
My app looks like this:
App.js
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import AuthTabs from './components/AuthTabs';
import NavigationTab from './components/NavigationTab';
import Amplify, { Auth } from 'aws-amplify';
import AWSConfig from './aws-exports';
Amplify.configure(AWSConfig);
export default class App extends React.Component {
state = {
isAuthenticated: false
}
authenticate(isAuthenticated) {
this.setState({ isAuthenticated })
}
render() {
if (this.state.isAuthenticated) {
console.log('Hello', Auth.user.username)
return(
<View style={styles.container}>
<Text style={styles.textStyle}>
Hello {Auth.user.username}!
</Text>
<NavigationTab
screenProps={
{authenticate: this.authenticate.bind(this)}
}
/>
</View>
)
}
return (
<View style={styles.container}>
<AuthTabs
screenProps={
{authenticate: this.authenticate.bind(this)}
}
/>
</View>
)
}
}
Any help would be much appreciated.
i have used it like this:
currentUser = () => {
Auth.currentAuthenticatedUser()
.then(user => {
console.log("USER", user);
this.props.navigation.navigate("App");
})
.catch(err => {
console.log("ERROR", err);
});
};
so, one can call it on the constructor on app refresh, and if the user is authenticated go to the main screen, but if it's not, stay in the login screen. Cheers.
I also have come up with a similar solution. But instead of the constructor, I use the life cycle method componentDidMount() to call a method that I named loadApp().
import React from 'react'
import {
StyleSheet,
View,
ActivityIndicator,
} from 'react-native'
import Auth from '#aws-amplify/auth'
export default class AuthLoadingScreen extends React.Component {
state = {
userToken: null
}
async componentDidMount () {
await this.loadApp()
}
// Get the logged in users and remember them
loadApp = async () => {
await Auth.currentAuthenticatedUser()
.then(user => {
this.setState({userToken: user.signInUserSession.accessToken.jwtToken})
})
.catch(err => console.log(err))
this.props.navigation.navigate(this.state.userToken ? 'App' : 'Auth')
}
render() {
return (
<View style={styles.container}>
<ActivityIndicator size="large" color="#fff" />
</View>
)
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
backgroundColor: '#aa73b7',
alignItems: 'center',
justifyContent: 'center',
},
})
loadApp() will try and get the user JWT Token by calling the AWS Amplify currentAuthenticatedUser() method. The obtained token is then stored in the component state.
I have used React navigation version 2 to navigate the user to either the App screen or the Auth stack screen depending on her status: logged in or not logged in.
Here is the way I handled this issue:
const currentUserInfo = await Auth.currentUserInfo()
if (currentUserInfo){
const data = await Auth.currentAuthenticatedUser()
dispatch({authTypes.FETCH_USER_DATA_SUCCESS, {payload: {user: data}}});
}
I have an Expo app, and I'm trying to handle push notifications sent while the app is in the foreground. It works fine in Android, but iOS it's crashing the app as it's received.
I have a push notification being sent from a Rails server:
params = ({
to: token.expo_push_token,
title: user.first_name,
sound: "default",
body: msg.body,
})
puts params
puts params.class
x = Net::HTTP.post_form(URI.parse('https://exp.host/--/api/v2/push/send'), params)
puts x.body
I can see in the server it sends:
Hash
app[worker.1]: {"data":{"id":"9058abf3-7352-4181-a69d-0b5fc8a8525c","status":"ok"}}
4 TID-godk4ew98 ExpoPushWorker JID-51b823f8feeaf42c313e392e INFO: done: 2.005 sec
And if the app is closed, the push notification appears on the lock screen. If the app is open in the foreground, nothing happens.
I want to listen for notifications when the app is open, and I have this in App.js:
import React from 'react';
import { StyleSheet, Text, View } from 'react-native';
import MessagesScreenRouter from './app/components/Router/MessagesScreenRouter';
import Sentry from 'sentry-expo';
import reducers from './app/reducers';
import { Provider } from 'react-redux';
import { createStore } from 'redux';
import { Notifications } from 'expo';
export default class App extends React.Component {
constructor(props) {
super(props)
this.state = {
notification: {},
}
this._handleNotification = this._handleNotification.bind(this)
}
_handleNotification = (notification) => {
console.log(notification)
this.setState({notification: notification});
};
componentWillUnmount(){
this._notificationSubscription && this._notificationSubscription.remove()
}
componentDidMount() {
this.notificationSubscription = Notifications.addListener(
(notification) => this._handleNotification(notification),
);
}
render() {
return (
<View style={{flex:1}}>
<StatusBar hidden={true} />
<View style={{height: 50, justifyContent: 'center', alignItems: 'center'}}>
<Text>Origin: {this.state.notification.origin}</Text>
<Text>Data: {JSON.stringify(this.state.notification)}</Text>
</View>
<Provider store={createStore(reducers)}>
<MessagesScreenRouter/>
</Provider>
</View>
);
}
}
I've tried many suggestions from tutorials all day, but I can not get this to work. What am I missing here?
You can't test it on simulator as expo docs states
Note: iOS and Android simulators cannot receive push notifications. To test them out you will need to use a real-life device. Additionally, when calling Permissions.askAsync on the simulator, it will resolve immediately with "undetermined" as the status, regardless of whether you choose to allow or not.
Just run exp publish and test it on expo client. Also you have to call for permission using Permissions.askAsync in the first place.
Doc's sample work like a charm, check it out: https://docs.expo.io/versions/v28.0.0/guides/push-notifications#__next
Expo has likely been updated in that aspect since then, and now it might even be using the command you have mentioned in the comment (exp start -m tunnel). As foreground notifications are still not available on iOS so far (which might have even caused your issue in the first place), this answer is rather for people looking to implement push notifications than fixing the issue above.
I have created a file downloader and previewer that shows both internal and external notifications on both OSes without running into such issues. The code is available on GitHub and an elaboration is given in this SO answer.
The most relevant code for this post is in regard to the use of local notifications from Expo while the app is in background, and showing them in foreground using toasts from the react-native-toast package. This functionality may be replaceable by Expo Notifications once this feature gets implemented.
For completeness, here is the code for the project:
App.js
import React, { Component } from 'react';
import { View, ScrollView, StyleSheet, Button, Alert, Platform, Text, TouchableWithoutFeedback } from 'react-native';
import { FileSystem, Constants, Notifications, Permissions } from 'expo';
import Toast, {DURATION} from 'react-native-easy-toast';
async function getiOSNotificationPermission() {
const { status } = await Permissions.getAsync(
Permissions.NOTIFICATIONS
);
if (status !== 'granted') {
await Permissions.askAsync(Permissions.NOTIFICATIONS);
}
}
export default class App extends Component {
constructor(props) {
super(props);
// this.toast = null;
this.listenForNotifications = this.listenForNotifications.bind(this);
// this.openFile = this.openFile.bind(this);
this.state = {
filePreviewText: ''
}
}
_handleButtonPress = () => {
let fileName = 'document.txt';
let fileUri = FileSystem.documentDirectory + fileName;
FileSystem.downloadAsync(
"https://raw.githubusercontent.com/expo/expo/master/README.md",
fileUri
).then(({ uri }) => {
console.log('Finished downloading to ', uri);
const localnotification = {
title: 'Download has finished',
body: fileName + " has been downloaded. Tap to open file.",
android: {
sound: true,
},
ios: {
sound: true,
},
data: {
fileUri: uri
},
};
localnotification.data.title = localnotification.title;
localnotification.data.body = localnotification.body;
let sendAfterFiveSeconds = Date.now();
sendAfterFiveSeconds += 3000;
const schedulingOptions = { time: sendAfterFiveSeconds };
Notifications.scheduleLocalNotificationAsync(
localnotification,
schedulingOptions
);
})
.catch(error => {
console.error(error);
Alert.alert(error);
});
};
listenForNotifications = () => {
const _this = this;
Notifications.addListener(notification => {
if (notification.origin === 'received') {
// We could also make our own design for the toast
// _this.refs.toast.show(<View><Text>hello world!</Text></View>);
const toastDOM =
<TouchableWithoutFeedback
onPress={() => {this.openFile(notification.data.fileUri)}}
style={{padding: '10', backgroundColor: 'green'}}>
<Text style={styles.toastText}>{notification.data.body}</Text>
</TouchableWithoutFeedback>;
_this.toast.show(toastDOM, DURATION.FOREVER);
} else if (notification.origin === 'selected') {
this.openFile(notification.data.fileUri);
}
// Expo.Notifications.setBadgeNumberAsync(number);
// Notifications.setBadgeNumberAsync(10);
// Notifications.presentLocalNotificationAsync(notification);
// Alert.alert(notification.title, notification.body);
});
};
componentWillMount() {
getiOSNotificationPermission();
this.listenForNotifications();
}
componentDidMount() {
// let asset = Asset.fromModule(md);
// Toast.show('Hello World');
}
openFile = (fileUri) => {
this.toast.close(40);
console.log('Opening file ' + fileUri);
FileSystem.readAsStringAsync(fileUri)
.then((fileContents) => {
// Get file contents in binary and convert to text
// let fileTextContent = parseInt(fileContents, 2);
this.setState({filePreviewText: fileContents});
});
}
render() {
return (
<View style={styles.container}>
<View style={styles.buttonsContainer}>
<Button style={styles.button}
title={"Download text file"}
onPress={this._handleButtonPress}
/>
<Button style={styles.button}
title={"Clear File Preview"}
onPress={() => {this.setState({filePreviewText: ""})}}
/>
</View>
<ScrollView style={styles.filePreview}>
<Text>{this.state.filePreviewText}</Text>
</ScrollView>
<Toast ref={ (ref) => this.toast=ref }/>
</View>
);
// <Toast
// ref={ (ref) => this.toast=ref }
// style={{backgroundColor:'green'}}
// textStyle={{color:'white'}}
// position={'bottom'}
// positionValue={100}
// opacity={0.8}
// />
}
}
const styles = StyleSheet.create({
container: {
flex: 1,
alignItems: 'center',
justifyContent: 'center',
paddingTop: Constants.statusBarHeight,
backgroundColor: '#ecf0f1',
},
buttonsContainer: {
flexDirection: 'row',
},
button: {
flex: 1
},
filePreview: {
flex: 1,
padding: 10,
},
toastText: {
color: 'white',
padding: 5,
justifyContent: 'flex-start',
},
});
package.json: Currently using forked repo, switch back when feature becomes available.
{
"name": "local-notification-with-ios",
"version": "0.0.0",
"description": "No description",
"author": null,
"private": true,
"main": "node_modules/expo/AppEntry.js",
"dependencies": {
"expo": "^32.0.0",
"react": "16.5.0",
"react-native": "https://github.com/expo/react-native/archive/sdk-32.0.0.tar.gz",
"prop-types": "^15.5.7",
"react-native-easy-toast": "git+https://github.com/SiavasFiroozbakht/react-native-easy-toast.git#6eed52f4d64c796cb49bdafcd7b3986cf5975d62"
}
}