웹 사이트에 대한 간단한 반응 기본 클라이언트가 있습니다. 로그인 페이지에서 로그인 코드를 수동으로 입력하거나 바코드 스캐너를 사용하여 스캔합니다. 나는 실제 장치와 에뮬레이터에서 응용 프로그램을 테스트 해 보았습니다. 사실 ipv4를 통해서만 테스트하고, 로그인 ipv6을 기본적으로 지원한다고 생각하는 fetch를 사용합니다.React Native : App Store 거부, IPv6 지원
앱이 오프라인 일 때 ipv6 네트워크를 통해 말하면 오프라인이되고 IPV6 네트워크에 있다는 것이 무엇을 의미하는지 이해할 수 없습니까?
앱이 오프라인 일 때 사용자에게 연결이 없다는 오류가 표시됩니다. 그래서 나는 그것이 어떻게 추락 할 수 있는지 모른다.
요청을 가져 오려면 시간 초과를 추가해야 문제를 해결할 수 있습니까?
그러나 응용 프로그램으로 인해 동일한 오류에 3 번 거부되는 :
는 login.js이다실적 -
2.1이 다시 제출 주셔서 감사합니다.
는 특히, 로그인을 도청하는 것은 여전히 충돌이 앱을 리드 : 우리 때의 IPv6 네트워크에 연결된 아이폰 실행 아이폰 OS 9.3.3에
앱 충돌합니다.
이
앱을 사용할 때 발생
- 오프라인
- 를 와이파이
에 우리는이 문제를 해결하는 데 도움이되는 자세한 충돌 로그를 첨부했습니다.
여기'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;
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();
그리고는하는 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 : http://www.ataomega.com/temp..suczkfac.crash http://www.ataomega.com/temp..hsbgdlod.crash
애플 노트에 따르면 오프라인 상태 및 WiFi 상태에서 "로그인"을 탭하면 앱이 다운되었다고합니다. 이것들은 두 개의 개별적인 테스트 케이스로 오프라인과 와이파이가 아닌 동시에 같은 의미를 가지지 않습니다. 이 잘못을 재현 할 수 있습니까? – Paulw11
불행히도. 앱은 내 테스트에서 결코 충돌하지 않습니다. ( 여기에 오류 로그가 있습니다. http://www.ataomega.com/temp..suczkfac.crash – Ataomega
크래시 덤프에 의미있는 백 트레이스가 없습니다. 일부 코드는 "abort()"라고 불렀습니다. 어떤 디버깅/충돌 분석 도구를 자바 스크립트에서 사용할 수 있는지 전혀 알지 못합니다. – Paulw11