React Native: App Store abandonment, IPv6 support

I have a simple client for interacting with a client for a website, on the login page it provides two options, enter the login code manually or scan it using a barcode scanner. I tested the application in a real device and emulator many times when it worked fine. In fact, I only test on ipv4 and to log in to im using fetch, which in my opinion supports ipv6 by default.

They talk on the ipv6 network, when the application is disconnected, I can’t understand what it means to be OFFLINE and be on the IPV6 network?

When the application is disconnected, I show the user an error that there is no connectivity. therefore, I do not know how this can happen.

should I add a timeout to request a request to fix the problem?

But the application is rejected 3 times due to the same error:

Performance - 2.1

Thank you for resending.

An application crash on an iPhone running iOS 9.3.3 connected to an IPv6 network when we:

In particular, clicking on the login still causes the application to crash.

This happened when your application was used:

  • Offline
  • In wifi

We include detailed crash logs to help resolve this issue.

Here is the .js login:

'use strict'; import React, { Component } from 'react'; import { Text, View, Image, TextInput, TouchableOpacity, ActivityIndicatorIOS, StyleSheet, Dimensions, AlertIOS, NetInfo, } from 'react-native'; import Camera from 'react-native-camera'; var { width, height } = Dimensions.get('window'); class Login extends Component { constructor(props){ super(props); this.state = { showProgress: false, showCamera: false, cameraType: Camera.constants.Type.back, barcode: true, isConnected: false, } } componentWillMount(){ NetInfo.isConnected.fetch().done((data) => { this.setState({ isConnected: data }) }); } _onBarCodeRead(e) { this.setState({ showCamera: false, barcodeData: e.data, logincode: e.data, success: true, }); this.onLoginPressed(); } render(){ if(this.state.showCamera) { return ( <Camera ref="cam" style={styles.container} onBarCodeRead={this._onBarCodeRead.bind(this)} type={this.state.cameraType}> </Camera> ); } else { var errorCtrl = <View />; if(!this.state.success){ errorCtrl = <Text style={styles.error}> {this.state.message} </Text>; } ///// Check login type if(this.state.barcode){ return( <View style={styles.container}> <Image style={styles.logo} source={require('image!logo')} /> <Text style={styles.heading}> Please use QR-Scanner to login,{'\n'} or enter the Login code manually. </Text> <TouchableOpacity onPress={this.onQrPressed.bind(this)} style={styles.button}> <Text style={styles.buttonText}>Use QR-Scanner</Text> </TouchableOpacity> <TouchableOpacity onPress={this.toManuall.bind(this)} > <Text style={styles.change}> Want to enter code manually? </Text> </TouchableOpacity> {errorCtrl} <ActivityIndicatorIOS animating={this.state.showProgress} size="large" style={styles.loader} /> </View> ); } else { return( <View style={styles.container}> <Image style={styles.logo} source={require('image!logo')} /> <Text style={styles.heading}> Please use QR-Scanner to login,{'\n'} or enter the Login code manually. </Text> <TextInput onChangeText={(text)=> this.setState({logincode: text})} style={styles.loginInput} placeholder={this.state.logincode}> </TextInput> <TouchableOpacity onPress={this.onLoginPressed.bind(this)} style={styles.button} > <Text style={styles.buttonText}>Log in</Text> </TouchableOpacity> <TouchableOpacity onPress={this.toBarcode.bind(this)} > <Text style={styles.change}> Want to use Barcode? </Text> </TouchableOpacity> {errorCtrl} <ActivityIndicatorIOS animating={this.state.showProgress} size="large" style={styles.loader} /> </View> ); } ///// } } onLoginPressed(){ if(this.state.isConnected){ /// do the validation var valid = false; if(this.state.logincode != undefined && this.state.logincode.includes('opencampus://') && this.state.logincode.includes('access_token=') && this.state.logincode.includes('refresh_token=') && this.state.logincode.includes('id=') && this.state.logincode.includes('name=') && this.state.logincode.includes('scheme=')){ var valid = true; } if(valid){ console.log('Login.ios: Attempting to log in with logincode ' + this.state.logincode); this.setState({showProgress: true}); console.log('Login.ios: calling AuthService class'); var AuthService = require('./AuthService'); AuthService.login({ logincode: this.state.logincode }, (results)=> { this.setState(Object.assign({ showProgress: false }, results)); console.log('Login.ios: AuthService execution finished.', results); if(results.success && this.props.onLogin){ this.props.onLogin(results); } }); } else { AlertIOS.alert( 'Invalid Input', 'Login code you entered is not valid. Be sure to paste the whole string starting with opencampus://' ); } } else { AlertIOS.alert( 'No Connection', 'Please check your internet connection.' ); } } onQrPressed(){ this.setState({ showCamera: true, }); } toManuall(){ this.setState({ barcode: false, }); } toBarcode(){ this.setState({ barcode: true, }); } } var styles = StyleSheet.create({ container: { backgroundColor: '#00a2dd', paddingTop: 40, padding: 10, alignItems: 'center', flex: 1, justifyContent: 'center' }, logo: { width: 141, height: 137, }, heading: { fontSize: 18, margin: 10, marginBottom: 20, color: '#FFFFFF', paddingTop: 50, }, change: { fontSize: 12, color: '#FFFFFF', marginTop:10, }, loginInput: { height: 50, marginTop: 10, padding: 4, fontSize: 18, borderWidth: 1, borderColor: '#FFFFFF', borderRadius: 0, color: '#FFFFFF' }, button: { height: 50, backgroundColor: '#48BBEC', borderColor: '#48BBEC', alignSelf: 'stretch', marginTop: 10, justifyContent: 'center', alignItems: 'center', borderRadius: 5 }, buttonText: { color: '#fff', fontSize: 24 }, loader: { marginTop: 20 }, error: { color: 'red', paddingTop: 10 } }); module.exports = Login; 

Here is AuthService.js:

 'use strict'; import React, { Component } from 'react'; var SQLite = require('react-native-sqlite-storage'); var DeviceInfo = require('react-native-device-info'); class AuthService extends Component { constructor(props) { super(props); this.state = { showProgress: false } this.errorCB = this.errorCB.bind(this); this.successCB = this.successCB.bind(this); } errorCB(err) { console.log("Auth Service: error: ", err); this.state.progress.push("Error: " + (err.message || err)); return false; } successCB() { } login(creds, cb){ var db = SQLite.openDatabase({name : "oc.db", location: 'default'}, this.successCB.bind(this), this.errorCB.bind(this)); var sql = 'CREATE TABLE IF NOT EXISTS users (' + 'access_token text NOT NULL,' + 'refresh_token text NOT NULL,' + 'userName text NOT NULL,' + 'userId text NOT NULL,' + 'userMail text NOT NULL,' + 'userSignature text NOT NULL,' + 'userSignatureFormat text NOT NULL,' + 'userCreated text NOT NULL,' + 'userAccess text NOT NULL,' + 'userLogin text NOT NULL,' + 'userStatus text NOT NULL,' + 'userTimezone text NOT NULL,' + 'userLanguage text NOT NULL,' + 'userRoles text NOT NULL,' + 'deviceId text NOT NULL,' + 'deviceName text NOT NULL,' + 'host text NOT NULL,' + 'active text NOT NULL' + ');'; db.executeSql(sql, [], this.successCB.bind(this), this.errorCB.bind(this) ); var LCode = creds.logincode; var codeSplited = LCode.split("://"); var codeSplited2 = codeSplited[1].split("?"); var appName = codeSplited[0]; var serverName = codeSplited2[0]; var splitedVars = codeSplited2[1].split("&"); var access_token = splitedVars[0].split("="); var access_token = access_token[1]; var refresh_token = splitedVars[1].split("="); var refresh_token = refresh_token[1]; var uid = splitedVars[2].split("="); var uid = uid[1]; var uname = splitedVars[3].split("="); var uname = uname[1]; var scheme = splitedVars[4].split("="); var scheme = scheme[1]; var device_id = DeviceInfo.getUniqueID(); var device_name = DeviceInfo.getDeviceName(); var locale = DeviceInfo.getDeviceLocale(); console.log('AuthService: Try to fetch from : ', serverName); console.log('request body: ', JSON.stringify({ uid: uid, refresh_token: refresh_token, token: access_token, device: device_id, device_name: device_name, })); fetch(scheme + '://' + serverName, { method: 'POST', headers: { 'Accept': 'application/json', 'Content-Type': 'application/json', 'language': locale, 'Authorization': 'Bearer ' + access_token, }, body: JSON.stringify({ uid: uid, refresh_token: refresh_token, token: access_token, device: device_id, device_name: device_name, }) }) .then((response)=> { return response; }) .then((response)=> { return response.json(); }) .then((results)=> { console.log(results); if(results['result'] == 1){ console.log('Auth Service: Login was successfull'); // User data var userName = results['session']['user']['name']; var userId = results['session']['user']['uid']; var userMail = results['session']['user']['mail']; var userSignature = results['session']['user']['signature']; var userSignatureFormat = results['session']['user']['signature_format']; var userCreated = results['session']['user']['created']; var userAccess = results['session']['user']['access']; var userLogin = results['session']['user']['login']; var userStatus = results['session']['user']['status']; var userTimezone = results['session']['user']['timezone']; var userLanguage = results['session']['user']['language']; var userRoles = results['session']['user']['roles']['2']; var host = results['session']['user']['host']; var active = 'yes'; //var userPicture = results['session']['user']['picture']; console.log('Auth Service: Lets save user data to database'); var query = "INSERT INTO users (access_token, refresh_token, userName, userId, userMail, userSignature, userSignatureFormat, userCreated, userAccess, userLogin, userStatus, userTimezone, userLanguage, userRoles, deviceId, deviceName, host, active) VALUES (?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?, ?)"; var params = [access_token, refresh_token, userName,userId,userMail,userSignature,userSignatureFormat,userCreated,userAccess,userLogin,userStatus,userTimezone,userLanguage,userRoles,device_id,device_name,host,active]; db.executeSql(query,params, this.successCB.bind(this), this.errorCB.bind(this) ); return cb({ success: true, userData: results['session']['user'] }); } else if(results['result'] == 0){ console.log('Auth Service: Login failed message is ' + results['message']); return cb({ success: false, message: results['message'] }); } else { console.log('Auth Service: Login failed error is ' + results['error_description']); return cb({ success: false, message: results['error_description'] }); } }) .catch((err)=> { console.log('AuthService: ' + err); return cb(err); }) .done(); } } module.exports = new AuthService(); 

And here is Index.js:

 "use strict"; import React, {Component, PropTypes} from 'react'; import { AppRegistry, NavigatorIOS, StyleSheet, TabBarIOS, View, Text, StatusBar, } from 'react-native'; var CourseList = require("./app/CourseList"); var Profile = require("./app/Profile"); import Icon from 'react-native-vector-icons/Ionicons'; var SQLite = require('react-native-sqlite-storage'); var Login = require("./app/Login"); var db = SQLite.openDatabase({name : "oc.db", location: 'default'}); StatusBar.setBarStyle('light-content'); class OpenCampus extends Component { constructor(props) { super(props); this.state = { selectedTab: "Courses", isLoggedIn: false, userId: null, }; } componentWillMount(){ var query = "SELECT * FROM users WHERE active='yes'"; var params = []; db.transaction((tx) => { tx.executeSql(query,params, (tx, results) => { var len = results.rows.length; if(len > 0){ let row = results.rows.item(0); this.setState({ isLoggedIn: true, userId: row.userId }); } }, function(){ console.log('index: Something went wrong'); }); }); } onLogin(results) { this.setState({ isLoggedIn: true, }); } logout() { console.log("Logout called from index"); var query = "DELETE FROM users WHERE userId=?"; var params = [this.state.userId]; db.transaction((tx) => { tx.executeSql(query,params, (tx, results) => { ///// check if there is other accounts on database, if yes, make first row active var query = "SELECT * FROM users WHERE active='yes'"; var params = []; db.transaction((tx) => { tx.executeSql(query,params, (tx, results) => { var len = results.rows.length; if(len > 0){ let row = results.rows.item(0); userId = row.userId; ///// Set new user active var query = "UPDATE users SET active='yes' WHERE userId=?"; var params = [userId]; db.transaction((tx) => { tx.executeSql(query,params, (tx, results) => { console.log('index: Active Account Changed'); }, function(){ console.log('index: Something went wrong'); }); }); /////// this.setState({ isLoggedIn: true, userId: userId, }); } else { this.setState({ isLoggedIn: false, userId: null, }); } }, function(){ console.log('index: Something went wrong'); }); }); ///// }, function(){ console.log('index: Something went wrong when logging out'); }); }); } _renderCourses() { return ( <NavigatorIOS style={styles.wrapper} barTintColor='#00a2dd' titleTextColor='#fff' tintColor='#ffffff' ref='RCourses' initialRoute={{ component: CourseList, title: 'Courses', passProps: {filter: 'Courses'}, }} /> ); } _renderRegister() { return ( <NavigatorIOS style={styles.wrapper} barTintColor='#00a2dd' titleTextColor='#fff' tintColor='#ffffff' ref='RRegister' initialRoute={{ component: CourseList, title: 'Register', passProps: {filter: 'Register'}, }} /> ); } _renderProfile() { return ( <NavigatorIOS style={styles.wrapper} barTintColor='#00a2dd' titleTextColor='#fff' tintColor='#ffffff' ref='RProfile' initialRoute={{ component: Profile, title: 'Profile', passProps: {filter: 'Profile'}, rightButtonTitle: 'Logout', onRightButtonPress: () => this.logout(), leftButtonTitle: 'Add Account', onLeftButtonPress: () => this.addnew(), }} /> ); } addnew() { console.log('Send user to login page to add new account'); //// Set old user to inactive var query = "UPDATE users SET active='no' WHERE active='yes'"; var params = [this.state.userId]; db.transaction((tx) => { tx.executeSql(query,params, (tx, results) => { //// Set login status to false so login screen will be shown console.log(results); this.setState({ isLoggedIn: false, userId: null, }); }, function(){ console.log('index: Something went wrong when adding new account'); }); }); } popAll(){ if(typeof this.refs.RCourses !== typeof undefined){ this.refs.RCourses.popToTop(); } if(typeof this.refs.RRegister !== typeof undefined){ this.refs.RRegister.popToTop(); } if(typeof this.refs.RProfile !== typeof undefined){ this.refs.RProfile.popToTop(); } } render() { if(!this.state.isLoggedIn){ console.log('index: User not logged in. redirecting to Login page.'); return( <Login onLogin={this.onLogin.bind(this)} /> ); } else { console.log('index: User is logged in lets show the content'); return ( <TabBarIOS tintColor={"#00a2dd"}> <Icon.TabBarItem title="Courses" iconName="ios-list-outline" selectedIconName="ios-list-outline" selected={this.state.selectedTab === "Courses"} onPress={() => { this.setState({ selectedTab: "Courses", }); this.popAll(); }}> {this._renderCourses()} </Icon.TabBarItem> <Icon.TabBarItem title="Register" iconName="ios-book" selectedIconName="ios-book" selected={this.state.selectedTab === "Register"} onPress={() => { this.setState({ selectedTab: "Register", }); this.popAll(); }}> {this._renderRegister()} </Icon.TabBarItem> <Icon.TabBarItem title="Profile" iconName="ios-person" selectedIconName="ios-person" selected={this.state.selectedTab === "Profile"} onPress={() => { this.setState({ selectedTab: "Profile", }); this.popAll(); }}> {this._renderProfile()} </Icon.TabBarItem> </TabBarIOS> ); } } } var styles = StyleSheet.create({ tabContent: { flex: 1, alignItems: "center", }, tabText: { color: "white", margin: 50, }, wrapper: { flex: 1, backgroundColor: '#00a2dd', } }); AppRegistry.registerComponent('OpenCampus', () => OpenCampus); 

UPDATE: here's the apple crash log: http://www.ataomega.com/temp..suczkfac.crash http://www.ataomega.com/temp..hsbgdlod.crash

+5
javascript ios iphone reactjs react-native
Aug 05 '16 at 7:21
source share
1 answer

You should check your application for ipv6 compatibility. Here is a tutorial that explains how to do this.

  • Download OS X 10.11
  • Make sure your Mac is connected to the Internet, but not over Wi-Fi.
  • Run the system settings from your Dock, LaunchPad or Apple menu.
  • Press the Option key and select Sharing. Do not release the Option key yet.
  • Select Internet Sharing from the list of sharing services.
  • Release the Option key.
  • Check the box next to "Create NAT64 Network."
  • Select a network interface that provides an Internet connection, such as Thunderbolt Ethernet.
  • Check the Wi-Fi box.
  • Click "Wi-Fi Settings" and configure the network name and security settings for your network.
  • Configure Wi-Fi LAN settings
  • Select the "Shared Internet" checkbox to enable the local area network.
  • When you are prompted to confirm that you want to start sharing, click "Start."
  • When sharing is active, you should see a green status indicator and a shortcut that says about using the Internet: incl. In the Wi-Fi menu, you will also see a small arrow indicating that Internet Sharing is turned on. You now have an IPv6 NAT64 network and you can connect to it from other devices to test your application.
+6
Aug 05 '16 at 7:30
source share



All Articles