小编典典

React Native:App Store拒绝,支持IPv6

reactjs

我有一个网站的简单本地客户端,在登录页面中提供了两种选择,手动输入登录代码或使用条形码扫描仪进行扫描。我已经在真实的设备和仿真器中测试了该应用,但很多时候它都运行良好。实际上,我仅通过ipv4进行测试,并使用获取功能登录我,我认为默认情况下支持ipv6。

他们说当应用程序离线时通过ipv6网络,我不明白脱机并处于IPV6网络意味着什么?

当应用离线时,我向用户显示错误,提示没有连接。所以我不知道它怎么会崩溃。

应该添加超时以获取请求来解决此问题?

但是由于相同的错误,该应用被拒绝了3次:

性能-2.1

感谢您的重新提交。

当我们执行以下操作时,您的应用程序在运行连接到IPv6网络的iOS 9.3.3的iPhone上崩溃:

具体来说,点击登录仍然会导致应用崩溃。

使用您的应用程序时发生了这种情况:

  • 离线
  • 在Wi-Fi上

我们已附上详细的崩溃日志,以帮助解决此问题。

这是login.js:

'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);

更新:这是苹果的崩溃日志:http :
//www.ataomega.com/temp..suczkfac.crash
http://www.ataomega.com/temp..hsbgdlod.crash


阅读 250

收藏
2020-07-22

共1个答案

小编典典

您应该测试您的应用程序的ipv6兼容性。这是一个说明如何执行此操作的教程。

  • 启动OS X 10.11
  • 确保Mac已连接到Internet,但未通过Wi-Fi连接。
  • 从Dock,LaunchPad或Apple菜单中启动系统偏好设置。
  • 按选项键,然后单击共享。请勿释放Option键。
  • Select Internet Sharing in the list of sharing services.
  • Release the Option key.
  • Select the Create NAT64 Network checkbox.
  • Choose the network interface that provides your Internet connection,
    such as Thunderbolt Ethernet.
  • Select the Wi-Fi checkbox.
  • Click Wi-Fi Options, and configure the network name and security options
    for your network.
  • Setting up local Wi-Fi network options
  • Select the Internet Sharing checkbox to enable your local network.
  • When prompted to confirm you want to begin sharing, click Start.
  • Once sharing is active, you should see a green status light and a label
    that says Internet Sharing: On. In the Wi-Fi menu, you will also see a
    small, faint arrow pointing up, indicating that Internet Sharing is enabled.
    You now have an IPv6 NAT64 network and can connect to it from other devices
    in order to test your app.
2020-07-22