Skip to content

Commit 80eb9b4

Browse files
authored
Major January 2021 update (#25)
See PR for details.
2 parents feae474 + afc5ec4 commit 80eb9b4

File tree

130 files changed

+10666
-10645
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

130 files changed

+10666
-10645
lines changed

.gitattributes

+3
Original file line numberDiff line numberDiff line change
@@ -1 +1,4 @@
11
*.pbxproj -text
2+
3+
# specific for windows script files
4+
*.bat text eol=crlf

.gitignore

+7-10
Original file line numberDiff line numberDiff line change
@@ -42,20 +42,17 @@ yarn-error.log
4242
buck-out/
4343
\.buckd/
4444
*.keystore
45+
!debug.keystore
4546

4647
# fastlane
47-
#
48-
# It is recommended to not store the screenshots in the git repo. Instead, use fastlane to re-generate the
49-
# screenshots whenever they are needed.
50-
# For more information about the recommended setup visit:
51-
# https://docs.fastlane.tools/best-practices/source-control/
52-
53-
*/fastlane/report.xml
54-
*/fastlane/Preview.html
55-
*/fastlane/screenshots
48+
fastlane/.env.*
49+
!fastlane/.env.default
50+
!fastlane/.env.example1
51+
fastlane/**/
52+
!fastlane/example1/
5653

5754
# Bundle artifact
5855
*.jsbundle
59-
56+
6057
# CocoaPods
6158
/ios/Pods/

README.md

+49-65
Original file line numberDiff line numberDiff line change
@@ -1,107 +1,91 @@
1-
Discourse Mobile App for a Single Site (with support for Push Notifications)
2-
---
1+
## Discourse Mobile App for a Single Site (with support for Push Notifications)
32

4-
Whitelisted iOS app for a single Discourse site that supports Push Notifications via OneSignal.
3+
Whitelisted iOS/Android app for a single Discourse site that supports push notifications via OneSignal.
54

6-
Built with React Native. Inspired by [DiscourseMobile](https://github.com/discourse/DiscourseMobile).
7-
8-
For a demonstration check out SWAPD or TekInvestor on the App Store or Google Play.
9-
10-
### Do not use this for Android, use web notifications instead
11-
12-
As of September 2018, this app's support for Android will be deprecated. There is now a better way to have notifications in Android from your Discourse site directly. In your Discourse instance, enable the `push notifications prompt` admin setting. This will now let users of your site in applicable browsers (incl. Chrome for Android) see a bar prompting them to enable notifications. And done!
13-
14-
Android-specific instructions below are now outdated.
5+
For a demonstration check out SWAPD or TekInvestor on the App Store or Google Play.
156

167
### Getting Started
178

18-
1. Install React Native.
19-
```
20-
npm install -g react-native-cli
21-
```
9+
1. Install your packages:
2210

23-
2. Install your packages:
24-
```
25-
npm install
11+
```bash
12+
yarn install
2613
```
2714

28-
3. Copy the contents of `default.variables.js` to `app.variables.js` to set your app's variables (site URL, app name, colors, marketing text, etc.).
15+
2. Link the iOS libraries via
2916

30-
4. In the `ios` folder (`cd ios`, run
17+
```bash
18+
cd ios && pod install
3119
```
32-
pod install
33-
```
34-
This will link the libraries in xCode.
3520

36-
5. To run the app locally use:
21+
3. And run the app in the simulator using:
3722

38-
```
23+
```bash
3924
react-native run-ios
25+
# or
26+
react-native run-android
4027
```
4128

42-
See the [React Native](https://facebook.github.io/react-native/docs/getting-started.html) docs for more details.
29+
See the [React Native](https://facebook.github.io/react-native/docs/getting-started.html) docs for more details.
4330

4431
### OneSignal setup
4532

46-
You need to open an account at OneSignal to be able to send Push Notifications (PNs) from your Discourse site, and receive them in the app. Steps:
33+
You need to open an account at OneSignal to be able to send Push Notifications (PNs) from your Discourse site, and receive them in the app. Steps:
4734

4835
- Register an App ID on the Apple portal (developer.apple.com)
49-
- Open an account with [OneSignal](https://www.onesignal.com) (free), create a new app, and generate certificates for iOS and Android
50-
- Create the provisioning profiles on the Apple portal. You need a distribution profile for pushing to TestFlight and the App Store, and likely an ad-hoc profile for testing quickly on your device. (Note that you may also need a development certificate for testing the app on your device. Step 2 above creates only the production certificate.)
51-
- Create an iCloud container and associate it with your App ID.
52-
53-
#### OneSignal Discourse Setup
54-
36+
- Open an account with [OneSignal](https://www.onesignal.com) (free), create a new app, and generate certificates for iOS and Android (see Onesignal documentation for steps on each platform)
5537
- Add the [discourse-onesignal](https://github.com/pmusaraj/discourse-onesignal/) plugin to your Discourse instance and configure it: enable notifications, add your OneSignal App ID and the OneSignal REST API key.
56-
- In your Discourse settings, add your site's home URL to `allowed user api auth redirects` (the app will redirect to your home URL once the user authorizes access for the app in Discourse).
57-
- ~And add the OneSignal API Endpoint `https://onesignal.com/api/v1/notifications` to `allowed user api push urls`.~ This step is no longer needed, because it causes Discourse to send a second request to OneSignal (which fails). If you have previously added this to your configuration, you should remove it once your app has been updated to include [this commit](https://github.com/pmusaraj/discourse-mobile-single-site-app/commit/c98ab1468ffb03030ff9793d17fe43af99d995a6).
38+
- in your app's `app.variables.js` file, add the OneSignal App ID
5839

59-
#### OneSignal updates to native code
40+
### Build and release using Fastlane
6041

61-
In your app code for either iOS or Android, you need to replace the placeholder OneSignal App ID with your app's OneSignal App ID.
42+
To simplify managing your app and keeping up with changes in the repo, you can use the included Fastlane scripts.
6243

63-
- For iOS, look for `ONESIGNAL_APP_ID` in `ios/DiscoSingle/AppDelegate.m`.
64-
- For Android, look for `DISCOSINGLE_ONESIGNAL_APP_ID` and `DISCOSINGLE_GOOGLE_PROJECT_NUMBER` in `android/app/build.gradle`. (You will get the Google Project Number while setting up OneSignal for your Android app.)
44+
#### Initial setup
6545

66-
You should now be ready to build and test the app. Note that in iOS, Push Notifications can only be tested on a real device, but the OneSignal console will show attempts to enable Push Notifications from a simulator.
46+
- Create a private git repository that Fastlane's `match` script uses to generate and update your app's certificates.
47+
- Copy the `fastlane/example1` folder and the `.env.example1` file and rename them using your app's name (for this guide, we will assume the copied items are `fastlane/yourapp` and `.env.yourapp`).
48+
- Update the variables in the folder and the ENV file, as well as the logo.png and splash.png images.
49+
- **iOS**: Create an App Store Connect API Key and follow the instructions in https://docs.fastlane.tools/app-store-connect-api/, and update the `fastlane/yourapp/key.json` file with the key
50+
details.
51+
- **Android**: generate or copy over your app's keystore and secrets in the respective files in `fastlane/yourapp`.
6752

68-
### Helpful Tools
53+
You should now be ready to run Fastlane scripts for your app's environment. by appending `--env yourapp` to any Fastlane commands.
6954

70-
#### Generating assets
71-
Use [generator-rn-toolbox](https://github.com/bamlab/generator-rn-toolbox) to setup icons and splash screens for the app:
55+
To update the app name and assets, run:
7256

7357
```
74-
npm install -g yo generator-rn-toolbox
75-
76-
yo rn-toolbox:assets --icon icon.png
77-
yo rn-toolbox:assets --splash splash.png --android
78-
yo rn-toolbox:assets --splash splash.png --ios
58+
cd fastlane
59+
fastlane switch --env yourapp
7960
```
8061

81-
#### Logo for login screen
82-
The logo file for the login screen is under `js/logo.png`. Replace it with your logo.
62+
To generate (or update) iOS certificates, run:
8363

84-
#### Android build using Gradle
85-
Follow the [official React Native](https://facebook.github.io/react-native/docs/signed-apk-android.html) instructions on generating a key and an APK for release. Then run
8664
```
87-
cd android && ./gradlew assembleRelease
65+
cd fastlane
66+
fastlane ios certificates --env yourapp
8867
```
89-
and find your release file under `android/app/build/outputs/apk/app-release.apk`.
90-
91-
#### Renaming your App
9268

93-
You can rename the app using `react-native-rename`. This is necessary for Android, because it's the only way to change the bundle ID.
69+
To build your app for iOS, run:
9470

9571
```
96-
npm install react-native-rename -g
97-
react-native-rename "NewName" -b com.yourco.yourappid
72+
cd fastlane
73+
fastlane ios install --env yourapp
74+
# will install the app on a connected device or simulator
75+
76+
fastlane ios release --env yourapp
77+
# will build and upload the app to TestFlight
78+
9879
```
9980

100-
(The bundle name specified by `-b` above only applies to Android, to change your iOS bundle ID, use Xcode.)
81+
To build your app for Android, run:
10182

102-
After renaming the app, you need to manually edit some files in subfolders under `android/app/src/main/java`, and replace `com.discosingle;` at the beginning of every file with your new bundle ID. The rename script does it for `MainActivity.java` and `MainApplication.java`, you need to manually do this for the remaining files.
83+
```
84+
cd fastlane
85+
fastlane android apk --env yourapp
86+
# will build an apk in android/app/build/outputs/apk/
10387
104-
### Troubleshooting
88+
fastlane android release --env yourapp
89+
# will create a bundle android/app/build/outputs/bundle/
10590
106-
- Android file uploads may fail. The app uses https://github.com/dahjelle/react-native-android-webview-file-image-upload to enable file uploads in WebView, but it's not tested with all versions of Android.
107-
- If you have already checked out the project, and renamed the app, you may run into a variety of file conflicts if you pull updates. This is especially the case if the React Native version in the project has been updated. This is normal, and a better course of action is to check out a fresh copy, and reapply your changes and the rename.
91+
```

android/app/BUCK android/app/_BUCK

File renamed without changes.

android/app/build.gradle

+34-21
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
buildscript {
22
repositories {
3-
maven { url 'https://plugins.gradle.org/m2/' } // Gradle Plugin Portal
3+
maven { url 'https://plugins.gradle.org/m2/' } // Gradle Plugin Portal
44
}
55
dependencies {
6-
classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:[0.12.1, 0.99.99]'
6+
classpath 'gradle.plugin.com.onesignal:onesignal-gradle-plugin:[0.12.9, 0.99.99]'
77
}
88
}
99

@@ -138,13 +138,12 @@ android {
138138
}
139139

140140
defaultConfig {
141-
applicationId "com.discosingle"
141+
applicationId ANDROID_APP_ID
142142
minSdkVersion rootProject.ext.minSdkVersion
143143
targetSdkVersion rootProject.ext.targetSdkVersion
144-
versionCode 1
145-
versionName "1.0"
146-
manifestPlaceholders = [onesignal_app_id: "DISCOSINGLE_ONESIGNAL_APP_ID",
147-
onesignal_google_project_number: "DISCOSINGLE_GOOGLE_PROJECT_NUMBER"]
144+
versionCode 37
145+
versionName "1.6"
146+
multiDexEnabled true
148147
}
149148
splits {
150149
abi {
@@ -161,6 +160,12 @@ android {
161160
keyAlias 'androiddebugkey'
162161
keyPassword 'android'
163162
}
163+
release {
164+
storeFile file(MYAPP_RELEASE_STORE_FILE)
165+
storePassword MYAPP_RELEASE_STORE_PASSWORD
166+
keyAlias MYAPP_RELEASE_KEY_ALIAS
167+
keyPassword MYAPP_RELEASE_KEY_PASSWORD
168+
}
164169
}
165170
buildTypes {
166171
debug {
@@ -169,7 +174,7 @@ android {
169174
release {
170175
// Caution! In production, you need to generate your own keystore file.
171176
// see https://facebook.github.io/react-native/docs/signed-apk-android.
172-
signingConfig signingConfigs.debug
177+
signingConfig signingConfigs.release
173178
minifyEnabled enableProguardInReleaseBuilds
174179
proguardFiles getDefaultProguardFile("proguard-android.txt"), "proguard-rules.pro"
175180
}
@@ -189,26 +194,34 @@ android {
189194
}
190195
}
191196

192-
packagingOptions {
193-
pickFirst '**/armeabi-v7a/libc++_shared.so'
194-
pickFirst '**/x86/libc++_shared.so'
195-
pickFirst '**/arm64-v8a/libc++_shared.so'
196-
pickFirst '**/x86_64/libc++_shared.so'
197-
pickFirst '**/x86/libjsc.so'
198-
pickFirst '**/armeabi-v7a/libjsc.so'
199-
}
200197
}
201198

202199
dependencies {
203200
implementation fileTree(dir: "libs", include: ["*.jar"])
201+
//noinspection GradleDynamicVersion
204202
implementation "com.facebook.react:react-native:+" // From node_modules
203+
implementation "androidx.swiperefreshlayout:swiperefreshlayout:1.0.0"
204+
implementation 'com.android.support:multidex:1.0.3'
205+
206+
debugImplementation("com.facebook.flipper:flipper:${FLIPPER_VERSION}") {
207+
exclude group:'com.facebook.fbjni'
208+
}
209+
210+
debugImplementation("com.facebook.flipper:flipper-network-plugin:${FLIPPER_VERSION}") {
211+
exclude group:'com.facebook.flipper'
212+
exclude group:'com.squareup.okhttp3', module:'okhttp'
213+
}
214+
215+
debugImplementation("com.facebook.flipper:flipper-fresco-plugin:${FLIPPER_VERSION}") {
216+
exclude group:'com.facebook.flipper'
217+
}
205218

206219
if (enableHermes) {
207-
def hermesPath = "../../node_modules/hermesvm/android/";
208-
debugImplementation files(hermesPath + "hermes-debug.aar")
209-
releaseImplementation files(hermesPath + "hermes-release.aar")
220+
def hermesPath = "../../node_modules/hermes-engine/android/";
221+
debugImplementation files(hermesPath + "hermes-debug.aar")
222+
releaseImplementation files(hermesPath + "hermes-release.aar")
210223
} else {
211-
implementation jscFlavor
224+
implementation jscFlavor
212225
}
213226
}
214227

@@ -219,4 +232,4 @@ task copyDownloadableDepsToLibs(type: Copy) {
219232
into 'libs'
220233
}
221234

222-
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)
235+
apply from: file("../../node_modules/@react-native-community/cli-platform-android/native_modules.gradle"); applyNativeModulesAppBuildGradle(project)

android/app/debug.keystore

2.2 KB
Binary file not shown.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,72 @@
1+
/**
2+
* Copyright (c) Facebook, Inc. and its affiliates.
3+
*
4+
* <p>This source code is licensed under the MIT license found in the LICENSE file in the root
5+
* directory of this source tree.
6+
*/
7+
package com.rndiffapp;
8+
9+
import android.content.Context;
10+
import com.facebook.flipper.android.AndroidFlipperClient;
11+
import com.facebook.flipper.android.utils.FlipperUtils;
12+
import com.facebook.flipper.core.FlipperClient;
13+
import com.facebook.flipper.plugins.crashreporter.CrashReporterPlugin;
14+
import com.facebook.flipper.plugins.databases.DatabasesFlipperPlugin;
15+
import com.facebook.flipper.plugins.fresco.FrescoFlipperPlugin;
16+
import com.facebook.flipper.plugins.inspector.DescriptorMapping;
17+
import com.facebook.flipper.plugins.inspector.InspectorFlipperPlugin;
18+
import com.facebook.flipper.plugins.network.FlipperOkhttpInterceptor;
19+
import com.facebook.flipper.plugins.network.NetworkFlipperPlugin;
20+
import com.facebook.flipper.plugins.react.ReactFlipperPlugin;
21+
import com.facebook.flipper.plugins.sharedpreferences.SharedPreferencesFlipperPlugin;
22+
import com.facebook.react.ReactInstanceManager;
23+
import com.facebook.react.bridge.ReactContext;
24+
import com.facebook.react.modules.network.NetworkingModule;
25+
import okhttp3.OkHttpClient;
26+
27+
public class ReactNativeFlipper {
28+
public static void initializeFlipper(Context context, ReactInstanceManager reactInstanceManager) {
29+
if (FlipperUtils.shouldEnableFlipper(context)) {
30+
final FlipperClient client = AndroidFlipperClient.getInstance(context);
31+
32+
client.addPlugin(new InspectorFlipperPlugin(context, DescriptorMapping.withDefaults()));
33+
client.addPlugin(new ReactFlipperPlugin());
34+
client.addPlugin(new DatabasesFlipperPlugin(context));
35+
client.addPlugin(new SharedPreferencesFlipperPlugin(context));
36+
client.addPlugin(CrashReporterPlugin.getInstance());
37+
38+
NetworkFlipperPlugin networkFlipperPlugin = new NetworkFlipperPlugin();
39+
NetworkingModule.setCustomClientBuilder(
40+
new NetworkingModule.CustomClientBuilder() {
41+
@Override
42+
public void apply(OkHttpClient.Builder builder) {
43+
builder.addNetworkInterceptor(new FlipperOkhttpInterceptor(networkFlipperPlugin));
44+
}
45+
});
46+
client.addPlugin(networkFlipperPlugin);
47+
client.start();
48+
49+
// Fresco Plugin needs to ensure that ImagePipelineFactory is initialized
50+
// Hence we run if after all native modules have been initialized
51+
ReactContext reactContext = reactInstanceManager.getCurrentReactContext();
52+
if (reactContext == null) {
53+
reactInstanceManager.addReactInstanceEventListener(
54+
new ReactInstanceManager.ReactInstanceEventListener() {
55+
@Override
56+
public void onReactContextInitialized(ReactContext reactContext) {
57+
reactInstanceManager.removeReactInstanceEventListener(this);
58+
reactContext.runOnNativeModulesQueueThread(
59+
new Runnable() {
60+
@Override
61+
public void run() {
62+
client.addPlugin(new FrescoFlipperPlugin());
63+
}
64+
});
65+
}
66+
});
67+
} else {
68+
client.addPlugin(new FrescoFlipperPlugin());
69+
}
70+
}
71+
}
72+
}

android/app/src/main/AndroidManifest.xml

+2-2
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,9 @@
1717
<activity
1818
android:name=".MainActivity"
1919
android:label="@string/app_name"
20-
android:configChanges="keyboard|keyboardHidden|orientation|screenSize"
20+
android:configChanges="keyboard|keyboardHidden|orientation|screenSize|uiMode"
2121
android:windowSoftInputMode="adjustResize"
22-
android:launchMode="singleTop">
22+
android:launchMode="singleTask">
2323
<intent-filter>
2424
<action android:name="android.intent.action.MAIN" />
2525
<category android:name="android.intent.category.LAUNCHER" />

android/app/src/main/java/com/discosingle/MainActivity.java

+5-1
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,13 @@
11
package com.discosingle;
22

3+
import android.os.Bundle;
34
import com.facebook.react.ReactActivity;
45

56
public class MainActivity extends ReactActivity {
6-
7+
@Override
8+
protected void onCreate(Bundle savedInstanceState) {
9+
super.onCreate(savedInstanceState);
10+
}
711
/**
812
* Returns the name of the main component registered from JavaScript.
913
* This is used to schedule rendering of the component.

0 commit comments

Comments
 (0)