React Native and Expo apps: local storage vs IndexedDB for client side data storage
AsyncStorage
Limitations: While AsyncStorage
is great for persistent local storage in React Native, it's not designed for storing very large amounts of data like a full-fledged database. It's essentially a key-value store, and large values can impact performance and potentially hit underlying platform limits or cause the app to consume a significant portion of the device's allocated storage for that app.JSON.parse(stored)
to load the timestamps, the entire string is parsed into a JavaScript array of objects in memory. If each of the 500 objects has a very long string for its note
property, the total memory consumed by this array can become substantial. This could lead to:
- Increased RAM consumption: Potentially slowing down the app or the device, especially on older or low-end phones with limited RAM.
- App crashes: In extreme cases, if the app tries to allocate too much memory, the operating system might terminate it.
JSON.stringify
) and back again for loading (JSON.parse
) takes time. The longer the strings within the notes, the more time these operations will take, potentially leading to noticeable delays when the app launches or when timestamps are saved.- Short (a few words/sentences): 500 timestamps with notes like "Meeting started," "Finished task," or even short sentences are unlikely to be an issue.
- Medium (a paragraph or two): 500 timestamps with notes of 100-200 words each would start to be a concern, potentially taking up a few megabytes. This is where you might start seeing performance dips on older devices.
- Long (multiple paragraphs, essays): If "long notes" means hundreds or thousands of words per note, then 500 such entries would almost certainly be an issue. You could be looking at tens of megabytes or more, which is generally too much for
AsyncStorage
and would definitely impact memory and performance.
-
Internal Storage (Private to App): This is where
AsyncStorage
(used by React Native) typically stores its data.- Limited Access: Each app gets its own isolated storage directory. Other apps cannot directly access this data without root permissions.
- No Hard Limit per se for
AsyncStorage
data within this space: Android doesn't impose a specific numerical limit (like, say, "50MB per app forAsyncStorage
"). Instead, the effective limit is the total free internal storage of the device. - User Data vs. App Size: This internal storage is distinct from the app's installation size. Your app's executable code, libraries, and assets take up space, and then the data it generates (like your timestamps and notes) consumes this internal storage further.
- Uninstall Clears: When a user uninstalls your app, all data in this internal storage is deleted.
-
External Storage (Shared, e.g., SD Card or shared internal storage partition):
- Apps can request permission to write to shared external storage (like the "Downloads" folder or a connected SD card).
- This is typically used for larger files that users might want to access with other apps or keep after uninstalling your app (e.g., exported CSV files).
- Permissions are required (e.g.,
READ_EXTERNAL_STORAGE
,WRITE_EXTERNAL_STORAGE
), and Android 10+ has introduced Scoped Storage, which makes it harder for apps to access arbitrary files outside their own directories or specific media/document types.
What happens when storage limits are reached?
Since AsyncStorage
uses the app's internal storage partition, the "limit" is effectively tied to the device's overall free internal storage.
-
"Storage Full" Warnings: Before an app itself hits an explicit quota, the Android OS will start showing "Storage Space Running Out" notifications to the user if the device's overall internal storage is low.
-
App Crash (Out of Memory/Storage):
- If your app attempts to write data to
AsyncStorage
(or any other internal storage mechanism) when the device's free internal storage is critically low, the write operation will fail. - If the data being loaded into memory from
AsyncStorage
(e.g., your 500 long notes) consumes too much RAM, the Android operating system's Low Memory Killer (LMK) might terminate your app to free up resources for other foreground processes or critical system functions. This would manifest as an app crash from the user's perspective.
- If your app attempts to write data to
-
Operation Failure:
- Specific
AsyncStorage
operations (likesetItem
) will simply fail and return an error if there isn't enough space. Your app should ideally catch these errors (usingtry...catch
blocks aroundAsyncStorage
operations) and inform the user that storage is full or the save failed. - If
AsyncStorage
itself has an internal implementation detail that uses SQLite or another database, that underlying storage mechanism might hit its own limits or file size maximums, but generally, the device's overall free space is the more common constraint for user data.
- Specific
-
User Intervention: The ultimate action when storage is full on an Android device is for the user to intervene by:
- Deleting other apps.
- Clearing cache data from various apps.
- Moving files (photos, videos) to external storage or cloud.
- Deleting downloaded content.
For your app with potentially long notes:
- You won't get a "warning" from
AsyncStorage
itself that you're about to hit a theoretical per-app limit. The issue will arise when the device's overall storage is low, or when the amount of data you're trying to load into RAM becomes excessive. - The biggest concern with 500 long notes isn't necessarily reaching a direct "storage limit" on disk, but rather the performance impact and memory consumption when loading and processing that large data set. If each note is, say, 1KB, 500 notes is 500KB, which is fine. If each note is 100KB, 500 notes is 50MB, which starts to become concerning for
AsyncStorage
and in-memory usage.
Therefore, for your current app, if "long notes" are truly a core feature and can contain substantial text, a more robust database solution (like expo-sqlite
) is strongly recommended to efficiently handle storage, retrieval, and memory management of that data. It's built for structured data and can manage large text fields much more gracefully than AsyncStorage
for such volumes.
No, you will generally not need any new explicit user-granted permissions for the Android app or the web app for using SQLite/IndexedDB in the way described.
Here's why:
For Android (and iOS) using Native SQLite:
- Internal Storage:
expo-sqlite
stores its database files in the app's internal storage. This storage is private to your app, meaning no other app can access it directly. - No Permissions Needed: Android (and iOS) automatically grants your app permission to read and write to its own internal storage. You do not need to declare
READ_EXTERNAL_STORAGE
orWRITE_EXTERNAL_STORAGE
permissions, as those are for shared external storage (like the Downloads folder or an SD card). - Expo handles it: Expo (and React Native itself) abstract away most of these underlying native permission details for internal storage.
For Web App using IndexedDB
(via SQL.js
from expo-sqlite
):
- Browser Storage:
IndexedDB
is a standard browser API for client-side storage. - No Permissions Needed (typically): Browsers generally allow web applications to use
IndexedDB
without requiring a specific user permission prompt, as long as the origin (yourhttps://ravisiyer.github.io
domain) is allowed to store data. This is different from, say, accessing the camera or geolocation, which do require explicit user consent. - Quota Management: Browsers manage the overall storage quota for an origin.
If the browser is critically low on disk space, it might prompt the user to free up space or could even clear data from less-visited origins, but this is handled by the browser/OS, not by a specific permission request from your app. The IndexedDB
storage is typically persistent and not cleared unless the user explicitly clears browser data for your site.
In summary:
You can implement the proposed SQLite solution for your timestamp data without worrying about adding new permission requests to your app's manifest (for Android) or new permission prompts to the user in the browser (for web). This keeps the user experience smooth and avoids friction associated with permission requests.
How it Works (Android/iOS):
- External Storage: This refers to storage that is accessible to other apps and potentially the user directly (e.g., the public Downloads folder, a dedicated folder on the user's SD card if present, or a shared partition of the internal storage).
- Permissions Required: To do this, your Android app would need to explicitly request
READ_EXTERNAL_STORAGE
andWRITE_EXTERNAL_STORAGE
permissions from the user.For iOS, similar permissions are needed for shared document directories. These are considered "dangerous" permissions and require a runtime prompt to the user. - Specific Paths: You would need to specify a path within accessible external storage (e.g.,
Environment.getExternalStorageDirectory()/YourAppFolder/database.db
on Android, or the equivalent on iOS).
Implications of External SQLite Storage:
-
User Awareness and Control:
- Pros: Yes, the user would definitely be more aware of the database file. They could potentially see it using a file manager, copy it, back it up manually, or even delete it directly. This gives them more control over their data.
- Cons: It also means the user could accidentally delete or corrupt the database file, leading to data loss for them.
-
Storage Room:
- Pros: This would indeed shift the burden of storage capacity to the user's device's overall external storage, which is usually much larger than an app's dedicated internal storage quota.
- Cons: You would still need to manage the overall size of the database. While the limit is higher, a very large database could still consume significant device space and impact performance if the user's device is already low on storage.
-
Permissions and User Friction:
- This is the biggest drawback. Requesting storage permissions introduces friction for the user. Many users are wary of granting such permissions, especially for an app that doesn't obviously need access to their general files (like a photo editor or file manager would). It can impact your app's installation rate and user trust.
-
Data Security and Privacy:
- Data stored on external storage is not private to your application. Other applications with the necessary permissions could potentially read or modify your database file. This is a significant security and privacy concern if the data is sensitive.
- App Uninstallation: Unlike internal storage, data on external storage is not automatically deleted when the user uninstalls your app. This means residual files might be left behind, which can be seen as clutter by users.
For Web Apps:
The concept of "external storage" doesn't directly apply to web apps in the same way it does for mobile. Browser storage mechanisms like IndexedDB
(which expo-sqlite
uses on the web) are fundamentally "internal" to the browser's management for a given origin. While IndexedDB
offers much higher limits than localStorage
, it's still managed by the browser within its allocated space for your website.
Conclusion:
While technically feasible for mobile, storing your SQLite database on external storage usually introduces more complexity and potential downsides (permissions, security, data management by user) than benefits for a simple personal utility app like a Timestamp Tracker. The standard practice of using internal storage (which expo-sqlite
does by default, and IndexedDB
does for web) is generally preferred for application data because it's secure, automatically handled by the OS, and doesn't require explicit user permissions.
On the web, your understanding is correct: the user is limited to using the browser's "internal" storage mechanisms, primarily IndexedDB
, for SQLite databases (via SQL.js
from expo-sqlite
). There is no concept of "external storage" on the web in the same way there is for mobile devices (where apps can write to user-accessible file systems like SD cards or public directories).
Web browsers sandbox websites for security and privacy reasons, limiting their access to the underlying file system. IndexedDB
is the most robust and high-capacity persistent storage API available for web applications within that sandbox.
You're right that there's a difference, but your conclusion about the "need and associated cost of having a server" for web app data isn't always the case for simple apps. Let's clarify:
The "Difference" in Local Storage:
- Mobile (Android/iOS): Native apps have robust and high-capacity local storage options (SQLite, Realm, Core Data on iOS, SharedPreferences/Room on Android).
These are designed for significant amounts of data, and do not require a server to store that data locally on the device. - Web: Web browsers also have local storage options (
localStorage
,sessionStorage
,IndexedDB
).For simple apps, IndexedDB
(whichexpo-sqlite
uses on the web) is a very capable, high-capacity, client-side database that does not require a server to store data locally within the browser.
The "Need for a Server" and Associated Costs:
The "need for a server to host the app's data in a database" primarily arises when your application requires data synchronization, multi-device access, or collaborative features.
- Synchronization: If a user creates data on their phone and wants it to appear on their tablet or desktop, a server-side database is almost always necessary to act as the central hub for that data.
- Multi-Device Access: Similarly, if the user accesses your app from multiple browsers or computers, the local
IndexedDB
in one browser won't be accessible by another. A server is needed. - Collaboration/Sharing: If multiple users need to view or modify the same data (e.g., a shared to-do list), a central server database is fundamental.
- Server-Side Logic/Processing: If your app needs to perform complex computations, heavy data processing, or integrate with external services that are better handled on a server, then a backend is required.
- Truly Massive Data: While
IndexedDB
offers large capacities (hundreds of MBs to GBs), if your app truly deals with petabytes of data, a server-side database is inevitable.
For a simple app like your Timestamp Tracker, where the data is personal to the user and not intended to be synced across devices or shared, IndexedDB
(used by expo-sqlite
on the web) is perfectly adequate for local data storage and does not incur server costs for the data itself.
The "cost and hassle of having another server" only comes into play if you decide to add the features (like multi-device sync or sharing) that necessitate a cloud backend. Until then, your simple React Native and Expo app can use local SQLite (on mobile) and local IndexedDB
(on web) effectively and without server costs for data storage.
Let's go through each point:
a) "Don't use backend server for storing data as backend server hosting costs will come into play as well as programming complexity for user credentials to avoid abuse of backend server by unknown persons. Also the backend server will have to be managed by somebody which is another problem for these free simple apps." * View: Completely correct. For apps strictly needing personal, client-side-only data without cross-device sync or sharing, a backend server introduces unnecessary cost, complexity, and management overhead, which defeats the purpose of a "free simple app."
b) "Don't use local storage for data as on web, the low limit of 5 MiB per origin will be in play."
* View: Completely correct. localStorage
is indeed too limited for any significant amount of structured user data on web platforms due to its low 5-10 MiB per origin limit and synchronous nature.
c) "Use IndexedDB for both Android (and iOS possibly in future) and web which has a data limit which is related to free storage space on user's main device storage. [So if the main storage area of the device has limited free space then the IndexedDB limit may come into play. But if the main storage area of the device has some Gigabytes of free space, the user will not encounter a limit for the app's IndexedDB data.]"
* View: Mostly correct, with a crucial clarification for mobile.
* For Web: Absolutely correct. On the web, using IndexedDB
(which expo-sqlite
leverages via SQL.js
) is the right approach. Its storage limit is indeed dynamic and proportional to the user's device's free storage, making it suitable for much larger datasets than localStorage
.
* For Android (and iOS): This is the clarification. While the concept is correct (using a high-capacity local database tied to device storage), it's not IndexedDB
directly. On Android and iOS, expo-sqlite
uses the native SQLite database engine built into those operating systems. Native SQLite also stores data in the app's internal storage, which is limited by the device's overall free space, not by a fixed small quota. So, you're using native SQLite on mobile and IndexedDB
on the web, both providing high-capacity, local, and server-cost-free storage.
d) "For web front-end hosting like GitHub Pages or Netlify, if some issue crops up, say, due to heavy traffic for the app, users have the option of setting up a localhost web server on their PC, install the web distributable files from the GitHub repo (or provided as a separate download) in appropriate directory used by the localhost web server, and then run the simple app on localhost web. Thus even for web app, lack of front-end hosting service is not a show-stopper." * View: Completely correct. This is an excellent point for ensuring the app's longevity and user access even if public hosting becomes problematic. Providing a simple way for users to run the web app locally enhances its robustness and resilience, making it truly "free" and independent of external services.
In summary, your learning is very well-articulated and demonstrates a solid understanding of these crucial architectural decisions for free, client-side-focused applications. The only minor adjustment is specifying "native SQLite" instead of "IndexedDB" for the mobile platforms, while still maintaining the core idea of using a high-capacity local database.
You're right that a backend server can indeed be hosted locally on a user's PC (e.g., a Node.js/Express server with a local MySQL or SQLite database). This approach genuinely eliminates the costs and remote management hassles associated with a cloud-hosted backend.
However, you've also accurately identified the trade-offs:
- Increased User Installation & Setup: The user would need to install Node.js, npm packages, a database server (like MySQL), and then manually start and stop the backend server process. This is a significantly higher bar for technical expertise and effort for the end-user compared to simply running a client-side web page or installing a mobile app that manages its data entirely locally.
- Management Overhead (for User): As you said, the user would be responsible for ensuring the backend is running when they want to use the app, managing its processes, and potentially troubleshooting local server issues.
- Performance: While it avoids network latency, the performance would still depend on the user's local machine resources.
My View:
Your clarification is valid. For free, simple apps, this local backend approach is a legitimate way to avoid remote hosting costs. However, it shifts the "hassle" from you (the developer/host) to the end-user, introducing a new layer of complexity for them.
This contrasts with purely client-side solutions like IndexedDB
(for web) and native SQLite (for mobile), which require zero user-side server setup or management, making the app truly "simple" from the user's perspective. The choice between these depends on whether the functionality absolutely requires a server-like environment (e.g., more complex data processing, very large databases that IndexedDB might struggle with, or specific security/access control requirements) vs. prioritizing the absolute simplest user experience for personal, client-only data.
For your Timestamp Tracker's current scope, sticking to IndexedDB
/native SQLite for local data aligns more perfectly with the goal of a "free simple app" that minimizes user setup.
Me: Another learning point for me is that I initially thought that I need not limit the size of the Note for a Timestamp entry as I felt that nowadays storage space has increase so much and we are only handling text in the note. I felt that I was being too conservative in thinking of a limit on size of the Note and so did not specify that. Now I think that that was a mistake. From an app's robustness point of view, it should not allow cases like user copy-pasting some huge text data into the Note. So I should have a limit for the size of the Note which could even be a big figure like say 5000 characters. But it should NOT be unlimited as that opens up a door for app crash or freeze if huge amount of text is copy-pasted into Note, either intentionally or by mistake. What do u say?
Gem agreed.
saveTimestampsToDb
which essentially performed a DELETE ALL
followed by a batch of INSERT
statements was a simplification to address your request for "minimal code changes" while getting SQLite working. However, for a proper relational database, it is highly inefficient for granular operations like adding, deleting, or updating a single record.Why Your Suggestion is Better:
Using specific INSERT
, UPDATE
, and DELETE
SQL statements for individual rows is the correct and most efficient way to interact with a database for these types of operations. ...
Gem provided the new code. When I went through the provided code (before trying it out, IIRC), I found a lot of issues. I had a few rounds with it but all the issues did not get resolved. Some of these issues (some were fixed in updated code provided but some were not fixed) are listed below:
- Why are you deleting timestamps on addTimestamp? The App.js I provided you at the beginning of the chat shows a modal to user about timestamps being full?
- Also have you missed out on warning user about Timestamps becoming full when a new timestamp addition (on launch or on add Timestamp) makes or will make timestamps full?
- You also seem to have dropped the new timestamp highlighting code that is there in the App.js I uploaded. Why?
- You have now added code to not do add then Timestamps are full but you are not giving a warning when you add the timestamp that makes it full. Please see my uploaded App.js for that code.
- How about Timestamp addition on launch? Are you doing that? And are you having similar checks there for timestamps full and timestamps getting full after addition of timestamp like in addtimestamp?
App.js
file to use SQLite instead of AsyncStorage
." That was clearly a wrong track and so that entire chat went on the wrong track. But I had some learnings which I will give below:expo-sqlite
(and many other Expo modules that rely on native device capabilities) does not work in a web browser environment. expo-sqlite
is designed for React Native (iOS, Android, and Expo Go/development builds), where it interacts with the native SQLite databases on those platforms."...localStorage
for your timestamp data. expo-sqlite
is indeed platform-specific to native environments and won't work on the web.To achieve cross-platform persistence with IndexedDB on the web and a suitable alternative on Android (like AsyncStorage, which localforage falls back to), I recommend using the localforage
library. localforage
is a JavaScript library that provides a simple API for storing data asynchronously in the browser using IndexedDB or WebSQL, and it can be configured to use AsyncStorage in React Native. This provides a unified API for your application logic.
Gem then provided the npx expo install instruction and modified App.js
I tried running that but ...
Me: On Android, I get this error: ERROR Error saving timestamps to localforage: [Error: No available storage method found.]
Gem suggested solutions over 2 or 3 rounds but none of them worked. I said I am giving up. Gem made some response. ...
Me: Can we use AsyncStorage on mobile but ensure that AsyncStorage on web uses IndexedDB
Gem: I understand you're feeling frustrated, but let's take one more shot at this with localforage
, as it's truly designed to handle the exact scenario you're aiming for: using IndexedDB
on the web (for larger storage capacity) and AsyncStorage
on mobile.
The reason it didn't work before was likely due to a combination of an incorrect package name for the AsyncStorage
driver and the precise order of configuration. localforage
has built-in support for IndexedDB
on web, and when you define the AsyncStorage
driver, it can correctly prioritize them.
Here's the definitive approach to achieve your goal using localforage
: ....
Gem gave code but I don't recall now whether I tried that code or not. I did not continue further with this chat. Chat is titled, "SQLite Integration for Timestamp App" and would be dated 19 Jun. 2025 or perhaps a day earlier.
Then I decided to revert to my earlier code and go for simple option of having limited number of timestamps and limit size of each note. That way I need not worry about web per origin data size limits.
I first made an attempt of having alerts if existing data had notes of over 500 characters. ...
Me: I want the following changes:
1) In Edit Note modal, the input box should accept a maximum of 500 characters only.
2) If existing timestamps data has one or more note fields of over 500 characters, on loading of timestamps data into the app, user should be presented with an alert that now the app has a maximum of 500 characters per Note. User should then be given a choice to
2a) Continue using the app in which case note data of over 500 characters will be truncated to 500 characters. If the user accepts this choice the app should truncate all note fields of over 500 characters to 500 characters.
2b) Export existing data and then exit the app
The intent of this change is to limit the maximum data the app will store in local storage, especially on web due to limit of 5 MiB on Chrome browser for a particular origin.
Gem provided some code but I faced some issues. So I reloaded my earlier App.js and asked for the simple change specified below. If I recall correctly, it provided code what had the earlier change specifications. I am getting the impression that Gem trips up on such different versions of App.js. So I switched to a new chat, uploaded my App.js and repeated the simple change request, which is given below. I had to cancel a new chat as it seemed to have got stuck but the next chat I started, "App.js Code Analysis and Summary", worked out well.
1) In Edit Note modal, the input box should accept a maximum of 500 characters only.
The intent of this change is to limit the maximum data the app will store in local storage, especially on web due to limit of 5 MiB on Chrome browser for a particular origin.
----
Gem provided code.
Me: Seems to be working. Thanks. Now can you calculate what is the maximum amount of data we may use in local storage for this app
Gem: The maximum amount of data this application might use in local storage can be calculated based on the MAX_TIMESTAMPS
and MAX_NOTE_LENGTH
constants defined in your App.js
file, along with the fixed size of other data fields.
Let's break down the size calculation for each timestamp entry:
id
: Generated usingDate.now().toString(36) + Math.random().toString(36).substring(2, 8)
. This typically results in a string of about 13-14 characters (e.g.,k5z8qj1
+abc123
). We'll consider 14 characters.time
: Stored as an ISO string (e.g.,"2024-06-19T17:30:00.000Z"
), which is 24 characters long.note
: The maximum length isMAX_NOTE_LENGTH
, which is 500 characters.
When stored in AsyncStorage
, these values are stringified into JSON. A single timestamp entry would look something like this (with actual values for demonstration):
{"id":"k5z8qj1abc123","time":"2024-06-19T17:30:00.000Z",
"note":"This is a sample note up to 500 characters..."}
Let's calculate the approximate size of one entry, including JSON overhead (quotes, commas, colons, curly braces):
id
data: 14 characterstime
data: 24 charactersnote
data: 500 characters- JSON structural characters (keys, quotes, colons, commas, braces):
{"id":"
(6 chars)","time":"
(8 chars)","note":"
(8 chars)"}
(2 chars)- Total structural characters: characters
Total characters per entry = characters.
The MAX_TIMESTAMPS
is set to 100.
Therefore, the maximum total data usage would be: .
Assuming each character is 1 byte (which is a common approximation for typical ASCII/UTF-8 data):
56,200 bytes
Converting this to MiB (Megabytes), where 1 MiB = bytes:
This amount (0.0536 MiB) is well within Chrome's typical 5 MiB local storage limit per origin, ensuring that the app's data storage will not be an issue for users.
Me: Terrific! We have ensured that users will not run into local storage data size issues for this app either on web or on Android. Am I right?
Gem: Yes, you are absolutely right!
By setting the MAX_TIMESTAMPS
to 100 and MAX_NOTE_LENGTH
to 500 characters, and given our calculation that the app's maximum data usage will be approximately 0.0536 MiB, you have effectively ensured that users will not run into local storage data size issues.
This calculated maximum is well within the typical local storage limits:
- Web (e.g., Chrome): Typically has a 5 MiB (5242.88 KB) limit per origin. Your app's usage is significantly lower than this.
- Android (React Native using
AsyncStorage
):AsyncStorage
on Android often uses SQLite under the hood, which generally has much higher limits (tens or hundreds of MiB) than browser local storage. Your app's usage will be trivial in comparison.
So, you've successfully addressed the potential data size concerns for both web and Android platforms.
------------
Next I moved to building a new release. npx expo-doctor gave some issues about upgrade to newer version of two packages:
expo-system-ui@5.0.8 - expected version: ~5.0.9
react-native@0.79.3 - expected version: 0.79.4
I updated the packages. That led to a problematic sequence of events which took quite some time to fix.
20 Jun 2025
I had to start a fresh build. IIRC, I deleted android folder and started from expo prebuild.
'.\gradlew.bat clean' gave an error:
Clean fabric-arm64-v8a, expo-modules-core-arm64-v8a
C/C++: CMake Error in CMakeLists.txt:
C/C++: Imported target "ReactAndroid::jsi" includes non-existent path
C/C++: "C:/Users/{Username}/.gradle/caches/8.13/transforms/ae792b9635deeb6cde658afdf6542403/transformed/react-android-0.79.3-debug/prefab/modules/jsi/include"
C/C++: in its INTERFACE_INCLUDE_DIRECTORIES.
.\gradlew.bat clean
command is failing because it's still referencing old cached files related to react-native@0.79.3
, even after you presumably deleted the android
folder and ran npx expo prebuild --clean
.This is a common issue where Gradle's caches can persist outdated information. To resolve this, you need to clear Gradle's cache completely. ...
Me: can I not delete only the problem package react-native@0.79.3 from .gradle cache? Otherwise all large files will be downloaded again. Currently the .gradle cache size is 6.6 GB.
Gem said it is not recommended.
So I deleted gradle caches directory - C:/Users/{Username}/.gradle/caches
Next I went through the clean build process again, IIRC. Delete android folder, expo prebuild ...
'.\gradlew.bat clean' again gave some error:
C/C++: "C:/Users/ravi-user/.gradle/caches/8.13/transforms/5a89f88737dcaf880ea21b9fdcb02480/transformed/fbjni-0.7.0/prefab/modules/fbjni/include"
C/C++: in its INTERFACE_INCLUDE_DIRECTORIES. ...
Gem suggested an "aggressive" cleanup - node_modules, gradle cache, npm cache etc.
I did not want to go for all that straight away.
Me: Let me delete and reinstall node_modules
I also faced some lock error (some file being locked by some process) for, IIRC, one of gradlew.bat clean comands. I either restarted the PC or logged out and logged in again, after which that lock error went away. I also disabled some Java extension in VSCode (as I would keep getting some messages about Java stuff when I would edit the gradle files) and checked that no Java extensions were enabled.
Deleting and reinstalling node_modules seems to have done the trick. Now the command '.\gradlew.bat clean' gave the message: "BUILD SUCCESSFUL in 36s".
Next I moved to '.\gradlew.bat assembleRelease' (IIRC). That too succeeded but took quite some time (some downloads) - "BUILD SUCCESSFUL in 21m 18s".
I had forgotten to add my keystore file and modifications to android/gradle.properties and android/app/build.gradle . That resulted in the APK install on phone failing to update the earlier app. Also the Google Play Protect option came up. I later saw that the android\app folder has debug.keystore. But I will cover this part in a separate post which will also cover fixing the Android app icon clipping issue. ... Here's that post: Android app icon clipping issue and fix; Checking signature in APK file and Android app.
Comments
Post a Comment