javascript - Expo 独立 android 应用程序在某些设备上崩溃
问题描述
我已经为 iOS 和 Android 创建了一个应用程序,在 iOS 的 testflight 以及模拟器(iOS 和 Android)中一切正常。我为 android 创建了一个构建 (APK) 并将其安装在多个设备上。在大多数设备上一切正常,但在某些 Android 设备上,应用程序在进入某个屏幕后崩溃并重新启动。如果我从该屏幕上删除所有代码并留下一个空白容器,它可以正常工作,如果我从屏幕上随机删除组件并且我删除的内容并不重要,它也可以工作。
这是一件非常奇怪的事情,因为当我在设备上使用具有调试模式的模拟器或 expo 客户端时,我没有收到任何错误消息,因此很难理解问题所在。
这是导致问题的页面中的代码。我没有选择,所以希望有人可以帮助我。
import React from "react";
import {fas} from "@fortawesome/pro-solid-svg-icons";
import { library } from '@fortawesome/fontawesome-svg-core';
import {withTranslation} from "react-i18next";
import styled from "styled-components";
import {colors} from "../../../../../assets/styles/variables";
import {Form, Toast, View} from "native-base";
import {Field, formValueSelector, reduxForm, getFormValues} from "redux-form";
import {connect} from "react-redux";
import {KeyboardAwareScrollView} from "react-native-keyboard-aware-scroll-view";
import RelationsSelector from "../../../../shared/components/selectors/relations/Selector";
import RegularTextInput from "../../../../shared/components/form/RegularTextInput";
import {fetchContacts, fetchRelation} from "../../../relations/actions";
import DateComponent from "./DateComponent";
import PaymentConditions from "../../../../shared/components/selectors/payment-conditions/PaymentConditions";
import LinesComponent from "./LinesComponent";
import {
calculateLineTotals,
calculateTotals,
editInvoiceLine,
getSalesInformation,
saveInvoice,
updateInvoice
} from "../actions";
import PickerInput from "../../../../shared/components/form/PickerInput";
import {LogBox} from "react-native"
import isEqual from 'lodash/isEqual';
import RichTextInput from "../../../../shared/components/form/RichTextInput";
import DateInput from "../../../../shared/components/form/DateInput";
import SwitchInput from "../../../../shared/components/form/SwitchInput";
import TextItem from "../../../../shared/components/form/TextItem";
import ContactsSelector from "../../../../shared/components/selectors/contacts/Selector";
import MultiPickerInput from "../../../../shared/components/form/MultiPickerInput";
import {saveQuotation, updateQuotation} from "../../../quotations/actions";
LogBox.ignoreAllLogs(true)
library.add( fas );
class EditComponent extends React.Component {
state = {
isLoading: false,
selectedLine: null,
paymentDays: 0,
validRelationVat: false,
footer_text: "",
noteOffset: 0,
footerTextOffset: 0,
address: "",
initialPaymentCondition: this.props.initialValue ? true : false
}
async componentDidMount() {
await this.props.getSalesInformation(this.props.type);
let template;
let currency;
// Set default template
if(!this.props.initialValue && this.props.templates) {
template = this.props.templates.find(template => template.default === 1) || this.props.templates[0];
this.props.change("template_id", template.id);
}
if(!this.props.initialValue?.id) {
this.props.change("create_update_id", 0)
this.props.change("full_number", "Concept");
}
if(this.props.invoice.concept === "1") {
this.props.change("full_number", "Concept");
}
if(!this.props.initialValue && this.props.currencies) {
currency = this.props.currencies.find(currency => currency.default === 1) || this.props.currencies[0];
this.props.change("currency_id", currency.id)
this.props.change("currency_rate", currency.rate)
}
if(!this.props.initialValue && this.props.attachments) {
const attachments = this.props.attachments.map(attachment => attachment.id);
this.props.change("attachments", attachments);
}
if(this.props.initialValue?.id) {
this.calculateTotals();
this.props.change("create_update_id", this.props.initialValue.id);
}
if(this.props.settings.tax_option && this.props.taxOptions?.length > 0) {
const selectedOption = this.props.taxOptions.find(option => option.value === this.props.settings.tax_option);
if(this.props.invoice && !this.props.invoice.tax_option) {
this.props.change("tax_option", selectedOption.value);
}
}
}
componentDidUpdate(prevProps, prevState, snapshot) {
if(this.props.onFormSave && this.props.onFormSave !== prevProps.onFormSave) {
this.onHandleSaveInvoice();
}
// If tax option is changing we have to edit the lines with the right line tax and ledger
if(prevProps.invoice && prevProps.invoice.tax_option && this.props.invoiceLines && (this.props.invoice.tax_option !== prevProps.invoice.tax_option)) {
const prevTaxOptions = this.props.taxOptions.find(option => option.value === prevProps.invoice.tax_option);
const taxOptions = this.props.taxOptions.find(option => option.value === this.props.invoice.tax_option);
if(!isEqual(prevTaxOptions.options, taxOptions.options)) {
setTimeout(function(){
alert(this.props.t("warning_change_tax"));
}.bind(this), 1000);
}
this.onHandleChangeLines();
}
}
componentWillUnmount() {
this.props.onCloseForm();
}
onHandleChangeLines() {
if(this.props.invoice.line) {
const taxOption = this.props.taxOptions.find(option => option.value === this.props.invoice.tax_option);
const currentTaxOption = this.props.tax.find(option => option.id === taxOption.options[0]);
const ledgers = this.props.ledgers.filter(option => currentTaxOption ? option.report_code === currentTaxOption.report_code : option).map(option => {
return {
label: option.description,
value: option.id
}
});
this.props.invoice.line.map(async(line, index) => {
line.tax_id = currentTaxOption.id;
line.ledger_account_id = ledgers[0].value;
const invoiceLine = await this.props.calculateLineTotals(line, this.props.taxOptions, true);
this.props.editInvoiceLine(index, invoiceLine);
});
this.calculateTotals();
}
}
calculateTotals() {
if(this.props.taxOptions) {
this.props.calculateTotals(this.props.taxOptions);
}
}
addNewLine() {
this.setState({selectedLine: null})
this.props.navigation.navigate("InvoicesLinesForm");
}
selectLine(id) {
this.setState({selectedLine: id});
const selectedLine = this.props.invoice.line[0];
this.props.navigation.navigate('InvoicesLinesForm', {invoiceLineId: id, ledgerId: selectedLine.ledger_account_id});
}
async onHandleSaveInvoice() {
let response;
if(this.props.invoice && this.props.invoice.id) {
// Update existing invoice
if(this.props.type === "sales_invoice") {
response = await this.props.updateInvoice(this.props.invoice.id);
}
if(this.props.type === "quotation") {
response = await this.props.updateQuotation(this.props.invoice.id);
}
} else {
// Save new Invoice
if(this.props.type === "sales_invoice") {
response = await this.props.saveInvoice();
}
if(this.props.type === "quotation") {
response = await this.props.saveQuotation();
}
}
if(response) {
if(response.success) {
Toast.show({
text: response.message,
duration: 3000,
type: "success"
});
this.props.reset();
this.props.onSaveSuccess(response.id);
}
if(response.error) {
if(Array.isArray(response.error)) {
Toast.show({
text: response.error.join('\n'),
buttonText: this.props.t("button_okay"),
duration: 5000,
type: "danger"
});
} else {
Toast.show({
text: response.error,
duration: 5000,
type: "danger"
});
}
}
} else {
alert(this.props.t("something_went_wrong"))
}
this.props.onHandleSave(response);
}
async onSelectRelation(id) {
if(id) {
const relation = this.props.relation;
this.props.change("relation_id", id);
this.setState({address: relation.street + " " + relation.house_number + ", " + relation.zip });
if(relation.payment_condition && !this.state.initialPaymentCondition) {
if(this.props.paymentConditions.find(option => option.id === relation.payment_condition)) {
this.props.change("payment_condition_id", relation.payment_condition);
this.onChangePaymentCondition(relation.payment_condition);
this.setState({initialPaymentCondition: false});
}
}
if(relation.vat_valid) {
this.setState({validRelationVat: true});
} else {
this.setState({validRelationVat: false});
}
}
this.props.fetchContacts({relation_id: id});
}
getTaxOptions() {
if(this.props.taxOptions) {
const taxOptions = this.state.validRelationVat ? this.props.taxOptions : this.props.taxOptions.filter(option => option.vat_check === 0);
const taxValues = taxOptions.map(option => {
return {
label: option.name,
value: option.value
}
});
return taxValues;
}
return [];
}
getTemplates() {
if(this.props.templates) {
return this.props.templates.map(option => {
return {
label: option.description,
value: option.id
}
});
}
return [];
}
getAttachments() {
if(this.props.attachments) {
return this.props.attachments.map(option => {
return {
label: option.description,
value: option.id
}
});
}
return [];
}
getCurrencies() {
if(this.props.currencies) {
return this.props.currencies.map(option => {
return {
label: option.currency,
value: option.id
}
});
}
return [];
}
onChangePaymentCondition(id) {
if(this.props.paymentConditions) {
const paymentCondition = this.props.paymentConditions.find(item => item.id === id);
if(this.props.type === "sales_invoice") {
this.setState({paymentDays: paymentCondition.days, footer_text: JSON.parse(paymentCondition.footer_text_invoice)});
}
if(this.props.type === "quotation") {
this.setState({paymentDays: paymentCondition.days, footer_text: JSON.parse(paymentCondition.footer_text_quotation)});
}
}
}
onHandleChangeCurrency(value) {
const currency = this.props.currencies.find(currency => currency.id === value);
if(currency) {
this.props.change("currency_rate", currency.rate);
this.calculateTotals();
}
}
render() {
return (
<Container>
<List>
<KeyboardAwareScrollView scrollEventThrottle={16} showsVerticalScrollIndicator={false}>
<Form>
<Content>
<Field
name="relation_id"
label={this.props.t("relation")}
onChange={(id) => this.onSelectRelation(id)}
placeholder={this.props.t("make_choice")}
component={RelationsSelector}
/>
<TextItem
value={this.state.address}
label={this.props.t("address")}
placeholder={this.props.t("street") + ", " + this.props.t("zip")}
/>
<Field
name="contact_name"
label={this.props.t("contact")}
placeholder={this.props.t("contact")}
multiline={false}
component={ContactsSelector}
isSearchContactsAvailable={this.props.invoice?.relation_id && this.props.contacts.length > 0}
/>
<Field
name="reference"
label={this.props.t("reference")}
placeholder={this.props.t("reference")}
multiline={false}
component={RegularTextInput}
/>
<Field
name="full_number"
label={this.props.t("number")}
placeholder={this.props.t("number")}
multiline={false}
component={RegularTextInput}
disabled
/>
<DateComponent paymentDays={this.state.paymentDays}/>
<Field
name="tax_option"
label={this.props.t("tax_options")}
placeholder={this.props.t("make_choice")}
data={this.getTaxOptions()}
component={PickerInput}
last
/>
</Content>
<Separator>
<SeparatorText>{this.props.t("invoice_lines")}</SeparatorText>
</Separator>
<LinesComponent
onHandleNewLine={()=> this.addNewLine()}
onHandleSelectLine={(id)=> this.selectLine(id)}
invoice={this.props.invoice}
lines={this.props.invoiceLines}
/>
<Separator>
<SeparatorText>{this.props.t("note")}</SeparatorText>
</Separator>
<Content style={{marginTop: 10}} onLayout={({nativeEvent}) => this.setState({noteOffset: nativeEvent.layout.y})}>
<Field
name="comment"
label={this.props.t("note")}
placeholder={this.props.t("note_placeholder")}
props={this.props}
component={RichTextInput}
onFocusInput={() => this.scroll.props.scrollToPosition(0, this.state.noteOffset)}
last
/>
</Content>
<Separator>
<SeparatorText>{this.props.t("footer_text")}</SeparatorText>
</Separator>
<Content style={{marginTop: 10}} onLayout={({nativeEvent}) => this.setState({footerTextOffset: nativeEvent.layout.y})}>
<Field
name="footer_text"
label={this.props.t("footer_text")}
placeholder={this.props.t("footer_text_placeholder")}
props={this.props}
component={RichTextInput}
html={this.state.footer_text}
onFocusInput={() => this.scroll.props.scrollToPosition(0, this.state.footerTextOffset)}
last
/>
</Content>
<Separator>
<SeparatorText>{this.props.t("extra_options")}</SeparatorText>
</Separator>
<Content style={{marginTop: 10}}>
<Field
name="template_id"
label={this.props.t("template")}
placeholder={this.props.t("make_choice")}
data={this.getTemplates()}
component={PickerInput}
/>
{this.props.currencies && this.props.currencies.length > 1 && (
<>
<Field
name="currency_id"
label={this.props.t("currency")}
placeholder={this.props.t("make_choice")}
data={this.getCurrencies()}
onChange={(value) => this.onHandleChangeCurrency(value)}
component={PickerInput}
/>
<Field
name="currency_rate"
label={this.props.t("currency_rate")}
placeholder={this.props.t("currency_rate")}
multiline={false}
component={RegularTextInput}
/>
</>
)}
{this.props.attachments && this.props.attachments.length > 0 && (
<Field
name="attachments"
label={this.props.t("attachments")}
placeholder={this.props.t("make_choice")}
component={MultiPickerInput}
items={this.getAttachments()}
/>
)}
{this.props.initialValue?.id && this.props.type === "sales_invoice" && (
<Field
name="dispute"
label={this.props.t("dispute")}
placeholder={this.props.t("dispute")}
explanation={this.props.t("dispute_explanation")}
multiline={false}
component={SwitchInput}
/>
)}
{this.props.invoice?.dispute === 1 && (
<Field
name="dispute_date"
label={this.props.t("dispute_date")}
placeholder={this.props.t("dispute_date")}
explanation={this.props.t("dispute_date_explanation")}
multiline={false}
component={DateInput}
/>
)}
<View style={{height: 1, backgroundColor: "white", marginTop: -1}}></View>
</Content>
</Form>
</KeyboardAwareScrollView>
</List>
</Container>
)
}
}
const mapStateToProps = (state, props) => {
const selector = formValueSelector('salesInvoiceEditForm');
const invoiceSelector = getFormValues('salesInvoiceEditForm');
return {
initialValues: props.initialValue,
relations: state.relations.results,
relation: state.relations.relation,
contacts: state.relations.contacts,
taxOptions: state.salesInvoices.configuration.tax_options,
tax: state.salesInvoices.configuration.tax,
templates: state.salesInvoices.configuration.templates,
currencies: state.salesInvoices.configuration.currencies,
attachments: state.salesInvoices.configuration.attachments,
ledgers: state.salesInvoices.configuration.ledgers,
paymentConditions: state.masterData.paymentConditions,
settings: state.config.settings,
invoice: invoiceSelector(state),
invoiceLines: selector(state, "line"),
};
};
EditComponent = connect(
mapStateToProps, {
fetchRelation,
fetchContacts,
getSalesInformation,
editInvoiceLine,
calculateLineTotals,
calculateTotals,
saveInvoice,
updateInvoice,
saveQuotation,
updateQuotation
}
)(reduxForm({
form: 'salesInvoiceEditForm',
enableReinitialize: true
})(EditComponent));
export default withTranslation()(EditComponent);
const Container = styled.View`
background: ${colors.primary}
flex: 1;
padding: 0;
`;
const List = styled.View`
background: ${colors.greyLight};
overflow: hidden;
flex: 1;
`;
const Separator = styled.View`
margin-left: 15px;
`;
const SeparatorText = styled.Text`
text-transform: uppercase;
font-size: 14px;
color: ${colors.textColor90};
`;
const Content = styled.View`
margin-top: 30px;
margin-bottom: 30px;
background: white;
border-color: ${colors.greyBorder};
border-top-width: 1px;
border-bottom-width: 1px;
`;
解决方案
推荐阅读
- kamailio - 在两个 Kamailio 服务器之间转发 SIP 请求
- android - 应用程序在后台时的参与时间计算
- python - PIL中“P”和“L”模式下的图像有什么区别?
- java - event.consume() 方法在 javafx 中不起作用
- php - CI中的多个mysql查询
- javascript - javascript中的await关键字会减慢应用程序的速度吗?
- amazon-web-services - 如何在不影响数据的情况下删除 DynamoDb 表中的范围键列?
- php - 如何在不使用 php artisan 的情况下创建 Laravel 开发服务器
- php - 如何在 Wordpress 的其他地方显示产品的价格
- ruby-on-rails - 从 rails 4.2 迁移到 5 问题需要降级 ActiveRecord 版本才能使用 1 个 gem