A hybrid mobile application offline eBook reader.
We at Infinite Library share the desire to create an open and excellent reading experience on as many devices as possible and to collaborate on an open-source project using modern technology. Hopefully our project increases access to eBooks around the world.
If on Windows:
If on OS X:
vagrant up
If using an emulator (replace IP address with your emulator's IP):
ADB_EMULATOR_IP_ADDRESS=192.168.56.101 vagrant up
This will start the virtual machine which is running the infinite-reader code copied from your host machine.
vagrant rsync-auto &
This will automatically sync changes from the host to the VM.
vagrant ssh -- -Y
tail -f /vagrant/react-native.log
The infinite-reader should now be deployed to the phone or emulator. Enable live reload using the "shake" gesture (Ctrl-m in Genymotion) and select "Enable Live Reload". Changes made to the code should automatically update on the device. To use the Chrome developer tools for debugging, start Chrome with:
google-chrome
Then connect to http://localhost:8081/debugger-ui with this Chrome instance and follow the instructions to install developer tools.
Setting up an Android development environment takes a few steps. Once you get set up, you will see how easy it is to develop Android apps with Javascript. The app looks and feels, and is, in more ways that not, a true native app.
Get set up here.
npm install -g react-native-cli
// may need to run as root npm install
Note: all warnings are fine, errors are not. If you get an error, you may need to adjust one or two things. npm will usually suggest a good fix. Once you get past this you are about ready to code.
If you have an Android device skip to 3.
react-native start
This will run the development enviroment. This is required so that if you make changes to you javascript and save, you can "reload js" on your device or emulator. On the device you can shake it to open the menu and on Genymotion you can click the menu on the lower right or use CMD-Mreact-native run-android
This will install the device to the device (or emulator). If you experience problems make sure that you have set up development mode on the device and that you have granted all development permissions in the settings.adb reverse tcp:8081 tcp:8081
this connects the device debug port to your computers debug portOn Android: You will probably get a "POST error" on a red screen. This is a known bug on the npm react-native-couchbase-lite module. The module should probably be part of the repo. For now, you must add the following to "/node_modules/react-native-couchbase-lite/index.js:148"
if (data) {
settings.body = JSON.stringify(data);
}
else { // add this!
//unresoved hack for error PUT must have a body and GET cant have body
if (settings.method == "PUT") {
settings.body = ".";
}
}
On Linux: To enable chrome debug you must change the mention of google-chrome
to chromium-browser
at "/node_modules/react-native/local-cli/server/middleware/getDevToolsMiddleware.js:19 and 23
ios/ReactNativeCouchbaseLiteExample.xcodeproj
in Xcode.npm install
and react-native start
.Here's the great part. The app is running a device database. When online, the database will sync with the server to get the latest in the catalog. The database is called couchbaseLite and there is an api to access the device db assets in the react-native-couchbase-lite npm module. Check it out.
Becuase we don't need a lot of routes here, the current app uses the Navigation component. Perhaps the best way to see how this works is to follow what happens when you click a book to open it. In CatalogCell.js there is a <TouchableElement>
. Awesome. When you select a book to read you touch this and onPress={this.props.onSelect}
is triggered.
What are "props"? I like to think of them as "pops" because, when you say this.props
, you are referencing the CatalogCell instance in whichever parent component it is used. So this.props.onSelect
fires the onSelect method of the <CatalogCell>
in Catalog.js. That in turn fires this.selectBook(book)
which in turn fires
this.props.navigator.push({
title: book.title,
name: 'reader',
book: book,
});
Here's props again, so we are sending information up to the navigator and the key is we are passing the next route with name:'reader'
. Name sets the route to go to next. Because all of the app essentially is wrapped in a Navigator component, the message arrives at the top-level component, which is the navigator, to set the route to "reader". The title and book are context variables for the next view. Understanding and tracing this path is the key to understanding not only how Navigator works but also how components work in React and React Native.
There are RN components and there are ones you create. The ones created are in "/app/android/components". Perhaps this diagram helps to explain the component structure as it (nearly) exists currently. RN components are in blue.