You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Android真机无法加载Google Sheets数据问题求助

Android真机无法连接Google Sheets,模拟器正常的排查与解决

我开发了一款Android应用,可将数据录入并存储至Google Sheets。在模拟器中运行时一切正常,能录入新数据且表格显示正常,但编译安装到真机后,数据无法加载、无法录入,应用始终处于加载状态。修改过Kotlin代码及Gradle配置,问题仍未解决。

相关Dart代码如下:

import 'package:gsheets/gsheets.dart';

class GoogleSheetsApi {
  // create credentials
  static const _credentials = r'''
  {
  "type": "service_account",
  "project_id": "fortunaapp1",
  "private_key_id": "50d7c550a7125c82dc99e3481f3441d8453bec68",
  "private_key": "-----BEGIN PRIVATE KEY-----
MIIEvgIBADANBgkqhkiG9w0BAQEFAASCBKgwggSkAgEAAoIBAQCUKlkegBFThU+Y
rUv0hIGyMR9Qna47+/63VBg0iSeZerszCdcaE3sVi7Jsde3OtM6716Cv9Xfz0nm+
ru7GYkMEHYLfx5cLHKKSW8AjmOVFNaiYZG1cgyR31LfvrAgnGChxNfgYu3dr24ae
LFO2GPsmBxQwob+bhwQgevkBfw9/DYCwqf9XA7e4EeoMQKskzcrKANRjVzz15A0u
P4y+c0JqFTqazYcU6xlrP7avB1Bu/Bjarz2U64/++pz+Bj7mv5sZWcivOhhcJN+Q
lQKVWEvDAWDlO7/lGbfI5mCjl9L56VsGZU4YjBcKkAQepVP6Vthn1ji07jAcarZ4
BEVieVYXAgMBAAECggEAKqTnooossnO/nYtfPaC3rYBK6YqAn94fCUfocZJ6Ncfn
wkBWSziJKAHdmC73A5Pxnonow0wsup39EV9K9QlKDZCq3tqUxAt5VROYQQacEmfn
vvjEqyhJoj20tQQ4Enx3A2KLph6qt/3miHbsnxAglOjbrEWZnttk2i5apc4auS/L
BfD+EtBnHW7UDNIcEGo1X2GU47FL0f5IV8lJH77SshiOfYM1QCL5SuDuWCqo+mWS
lRZEJFWH83hH7/UEr/aO1oLj67twylvQtqjuBekt+1bJyVsQB8BeMPZwQMOMUbiQ
G73u0eil2fMCRmQJtJZePkZWhR1LBNrWNRavqDbQZQKBgQDKUPaphatXrlzBv+Cg
FXcEtuo8KRh6FrQmzLG6kufb3L8iGs9ta3QqQS1JyUBWisJrL0itRemjlrnACJwe
wXOpRdjDLPYYa/dadxOpRop1+8gJDCgcQ1+aCKyWvjoEWeRlkDR3Ypp3eEQdIfvX
viFdpeQgBfpvjgEocLVV/hweJQKBgQC7ewAM2d5ik/4WFTQGOKC1pQHW61Cz/js/
jee8bW/Uf8nC1UvLujkMHX6cW3BUxmTBgm3bActr74O7rxQqfNv3L6dzhx6U63CV
oWtMf4SDqv9gOEkgqli33nEa1En1BC59vWNvFaj9YQ89WKlnDfYutlju+kPiunSB
qKVRI2OYiwKBgHa0EkVcfC+xyhKTtgO3FGHbwIsTwZzAfWrWZuEFGKzTVAF6oYGd
rkasfxnvzqP4PiINWCLyBidJZCrb4l3ZOzdyF8BMPQgPMM4PV6XWEZ8v3yoPy+jp
TspdlIXNjtTGuU8t0NrLK740/iHpso3erEz57GMtnsadFujXWE3gDjdRAoGBAIAk
63zdMebZVvPLHFsgO6DMnzxCbVAJ9n9TRFED0EtD6SlV10/yAmoogtDmoxoe3OFz
gBkQ2fT1qmoPmk4MN+F13hPWCG4rmzF7Orb39iB1McaX0kwUgz1yOobnEYH6kLh7
Scq02GQQAnWg83EwFtQI6TK3Ns1zOo0hM5YJBVtPAoGBAJonEAcUG3Vz9EGzDOUA
+0Ju7edU6iXhVN8oTEFUPAh7KpqwvfRXdjBAPvf9AW2wm1TIZSpqLwZ3L62m8nQb
pCXa5XZE/mOAxorJNHu/HvD2xGttn3yAC0y9a3QI0zf2wXkfE2o/vuwLifwRnJvw
aMmn/UhoRJertqcGpN7GTIQh
-----END PRIVATE KEY-----
",
  "client_email": "fortuna@fortunaapp1.iam.gserviceaccount.com",
  "client_id": "118121372819582547029",
  "auth_uri": "https://accounts.google.com/o/oauth2/auth",
  "token_uri": "https://oauth2.googleapis.com/token",
  "auth_provider_x509_cert_url": "https://www.googleapis.com/oauth2/v1/certs",
  "client_x509_cert_url": "https://www.googleapis.com/robot/v1/metadata/x509/fortuna%40fortunaapp1.iam.gserviceaccount.com"
}
  ''';

  // set up & connect to the spreadsheet
  static final _spreadsheetId = '1_om4BImQtpn3SjehwztKosEvmHQx9cRHQRrZeJkWKfY';
  static final _gsheets = GSheets(_credentials);
  static Worksheet? _worksheet;

  // some variables to keep track of..
  static int numberOfTransactions = 0;
  static List<List<dynamic>> currentTransactions = [];
  static bool loading = true;

  // initialise the spreadsheet!
  Future init() async {
    final ss = await _gsheets.spreadsheet(_spreadsheetId);
    _worksheet = ss.worksheetByTitle('Sheet1');
    countRows();
  }

  // count the number of notes
  static Future countRows() async {
    while ((await _worksheet!.values
            .value(column: 1, row: numberOfTransactions + 1)) !=
        '') {
      numberOfTransactions++;
    }
    // now we know how many notes to load, now let's load them!
    loadTransactions();
  }

  // load existing notes from the spreadsheet
  static Future loadTransactions() async {
    if (_worksheet == null) return;

    for (int i = 1; i < numberOfTransactions; i++) {
      final String dataNama = 
          await _worksheet!.values.value(column: 1, row: i + 1);
      final String dataPaspor = 
          await _worksheet!.values.value(column: 2, row: i + 1);
      final String dataSponsor = 
          await _worksheet!.values.value(column: 3, row: i + 1);
      final String dataTanggal = 
          await _worksheet!.values.value(column: 4, row: i + 1);

      if (currentTransactions.length < numberOfTransactions) {
        currentTransactions.add([
          dataNama,
          dataPaspor,
          dataSponsor,
          dataTanggal,
        ]);
      }
    }
    print(currentTransactions);
    // this will stop the circular loading indicator
    loading = false;
  }

  // insert a new transaction
  static Future insert(
      String nama, String paspor, String sponsor, String tanggal) async {
    if (_worksheet == null) return;
    numberOfTransactions++;
    currentTransactions.add([
      nama,
      paspor,
      sponsor,
      tanggal,
    ]);
    await _worksheet!.values.appendRow([
      nama,
      paspor,
      sponsor,
      tanggal,
    ]);
  }
}

排查与解决步骤

1. 网络权限检查

确保AndroidManifest.xml中添加了必要的网络权限:

<uses-permission android:name="android.permission.INTERNET" />
<uses-permission android:name="android.permission.ACCESS_NETWORK_STATE" />

Android 9及以上版本默认限制明文流量,Google Sheets API使用HTTPS无需额外配置,但如果有自定义域名需配置network_security_config.xml。

2. 服务账号与Spreadsheet权限验证

  • 确认目标Google Sheets已共享给代码中的client_email(fortuna@fortunaapp1.iam.gserviceaccount.com),权限至少设为编辑者。
  • 登录Google Cloud控制台,检查对应项目是否启用了Google Sheets API,且服务账号未被限制API访问权限。

3. 添加异常处理,避免加载状态卡死

原代码未处理任何网络或API异常,一旦请求失败会导致loading一直为true。修改关键方法添加异常捕获:

修改init方法:

Future init() async {
  try {
    final ss = await _gsheets.spreadsheet(_spreadsheetId);
    _worksheet = ss.worksheetByTitle('Sheet1');
    await countRows();
  } catch (e) {
    print('初始化失败: $e');
    loading = false; // 出错时强制停止加载
  }
}

修改countRows方法:

static Future countRows() async {
  if (_worksheet == null) {
    loading = false;
    return;
  }
  try {
    while ((await _worksheet!.values.value(column: 1, row: numberOfTransactions + 1)) != '') {
      numberOfTransactions++;
    }
    await loadTransactions();
  } catch (e) {
    print('统计行数失败: $e');
    loading = false;
  }
}

修改loadTransactions方法:

static Future loadTransactions() async {
  if (_worksheet == null) {
    loading = false;
    return;
  }
  try {
    currentTransactions.clear();
    // 修复循环条件,避免漏掉最后一行数据
    for (int i = 1; i <= numberOfTransactions; i++) {
      final String dataNama = await _worksheet!.values.value(column: 1, row: i + 1);
      final String dataPaspor = await _worksheet!.values.value(column: 2, row: i + 1);
      final String dataSponsor = await _worksheet!.values.value(column: 3, row: i + 1);
      final String dataTanggal = await _worksheet!.values.value(column: 4, row: i + 1);

      currentTransactions.add([dataNama, dataPaspor, dataSponsor, dataTanggal]);
    }
    print(currentTransactions);
  } catch (e) {
    print('加载数据失败: $e');
  } finally {
    loading = false; // 无论成功失败都停止加载
  }
}

4. 优化数据加载方式,减少网络请求

原代码循环调用单个单元格查询,网络请求次数过多易超时。改用批量获取整行数据:

static Future loadTransactions() async {
  if (_worksheet == null) {
    loading = false;
    return;
  }
  try {
    // 批量获取第2行开始的所有数据行(假设第1行是表头)
    final rows = await _worksheet!.values.allRows(fromRow: 2, length: numberOfTransactions);
    currentTransactions = rows.map((row) => row.take(4).toList()).toList();
    print(currentTransactions);
  } catch (e) {
    print('加载数据失败: $e');
  } finally {
    loading = false;
  }
}

5. 真机网络环境测试

  • 切换Wi-Fi和移动数据,测试不同网络环境下的连接情况。
  • 确认真机网络可正常访问Google相关服务,部分地区需检查网络是否存在访问限制。

内容的提问来源于stack exchange,提问作者Theo Haganta

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.28 17:22:42