Skip to content

Commit 62dfe29

Browse files
committed
feature: Keep Awake
There are other React Native modules to use this feature[1], but unfortunately we get race condition on Android because two pieces of asynchronous code are manipulating window flags at the same time, and it might work or not depending on the device you're using. This fixes the problem by implementing Keep Awake directly in this module so that we can add some extra glue on Android and make sure things will work as intended. * Use the keepAwake prop on UnityView to turn this on and off 1: e.g. @sayem314/react-native-keep-awake
1 parent 7ebd11c commit 62dfe29

File tree

7 files changed

+79
-5
lines changed

7 files changed

+79
-5
lines changed

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,8 @@ export default function App() {
3434
<UnityView
3535
style={{flex: 1, justifyContent: "flex-end"}}
3636
onMessage={onMessage}
37-
onReady={onReady}>
37+
onReady={onReady}
38+
keepAwake={true}>
3839
<View
3940
style={{
4041
flexDirection: "row",

android/src/main/java/no/fuse/rnunity/RNUnityManager.java

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@
88
import android.view.ViewGroup;
99
import android.view.ViewParent;
1010
import android.view.Window;
11+
import android.view.WindowManager;
1112

1213
import com.facebook.react.bridge.LifecycleEventListener;
1314
import com.facebook.react.bridge.ReactApplicationContext;
@@ -42,6 +43,8 @@ public String getName() {
4243
protected UnityPlayer createViewInstance(@Nonnull ThemedReactContext reactContext) {
4344
Log.d("RNUnityManager", "createViewInstance");
4445

46+
final RNUnityModule module = RNUnityModule.getInstance();
47+
4548
final Activity activity = reactContext.getCurrentActivity();
4649
final Handler handler = new Handler(Looper.getMainLooper());
4750

@@ -75,8 +78,19 @@ public void run() {
7578
activity.runOnUiThread(new Runnable() {
7679
@Override
7780
public void run() {
78-
Log.d("RNUnityManager", "Resetting window flags");
79-
window.setFlags(windowFlags, -1);
81+
int flags = windowFlags;
82+
boolean keepAwake = module.getKeepAwake();
83+
84+
// Race condition: Keep awake might be enabled or disabled after
85+
// the original flags were saved
86+
if (keepAwake) {
87+
flags |= WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
88+
} else {
89+
flags &= ~WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON;
90+
}
91+
92+
Log.d("RNUnityManager", "Resetting window flags; keepAwake=" + keepAwake);
93+
window.setFlags(flags, -1);
8094
}
8195
});
8296

@@ -86,7 +100,7 @@ public void run() {
86100
player.resume();
87101

88102
// Notify the app that Unity is ready to receive messages
89-
RNUnityModule.getInstance().emitEvent("ready", "");
103+
module.emitEvent("ready", "");
90104

91105
return player;
92106
}

android/src/main/java/no/fuse/rnunity/RNUnityModule.java

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,10 @@
11

22
package no.fuse.rnunity;
33

4+
import android.app.Activity;
5+
import android.util.Log;
6+
import android.view.WindowManager;
7+
48
import com.facebook.react.bridge.ReactApplicationContext;
59
import com.facebook.react.bridge.ReactContext;
610
import com.facebook.react.bridge.ReactContextBaseJavaModule;
@@ -17,9 +21,12 @@ public static RNUnityModule getInstance() {
1721
return instance;
1822
}
1923

24+
boolean keepAwake;
25+
2026
public RNUnityModule(ReactApplicationContext reactContext) {
2127
super(reactContext);
2228
instance = this;
29+
keepAwake = false;
2330
}
2431

2532
@Override
@@ -47,4 +54,29 @@ public void addListener(String eventName) {
4754
public void removeListeners(Integer count) {
4855
// Dummy method
4956
}
57+
58+
public boolean getKeepAwake() {
59+
return keepAwake;
60+
}
61+
62+
@ReactMethod
63+
public void setKeepAwake(boolean enabled) {
64+
keepAwake = enabled;
65+
final Activity activity = getCurrentActivity();
66+
67+
if (activity != null) {
68+
activity.runOnUiThread(new Runnable() {
69+
@Override
70+
public void run() {
71+
if (keepAwake) {
72+
Log.d("RNUnityModule", "Turning on keep awake");
73+
activity.getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
74+
} else {
75+
Log.d("RNUnityModule", "Turning off keep awake");
76+
activity.getWindow().clearFlags(android.view.WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);
77+
}
78+
}
79+
});
80+
}
81+
}
5082
}

example/App.tsx

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,8 @@ export default function App() {
77
<UnityView
88
style={{flex: 1, justifyContent: "flex-end"}}
99
onMessage={onMessage}
10-
onReady={onReady}>
10+
onReady={onReady}
11+
keepAwake={true}>
1112
<View
1213
style={{
1314
flexDirection: "row",

ios/RNUnity/RNUnity.m

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,4 +167,10 @@ - (void)emitEvent:(NSString *)name data:(NSString *)data {
167167
}
168168
}
169169

170+
RCT_EXPORT_METHOD(setKeepAwake:(BOOL)keepAwake) {
171+
dispatch_async(dispatch_get_main_queue(), ^{
172+
[[UIApplication sharedApplication] setIdleTimerDisabled:keepAwake];
173+
});
174+
}
175+
170176
@end

src/UnityModule.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,11 @@ export interface UnityModule {
3030
* @param message The argument to pass.
3131
*/
3232
sendMessage(gameObject: string, methodName: string, message: string): void
33+
34+
/**
35+
* Sets whether the screen should stay on.
36+
*/
37+
setKeepAwake(enabled: boolean): void
3338
}
3439

3540
class UnityModuleImpl implements UnityModule {
@@ -94,6 +99,10 @@ class UnityModuleImpl implements UnityModule {
9499
sendMessage(gameObject: string, methodName: string, message: string) {
95100
RNUnity.sendMessage(gameObject, methodName, message)
96101
}
102+
103+
setKeepAwake(enabled: boolean) {
104+
RNUnity.setKeepAwake(enabled)
105+
}
97106
}
98107

99108
export const UnityModule: UnityModule = new UnityModuleImpl()

src/UnityView.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,9 @@ export interface UnityViewProps extends ViewProps {
1111

1212
/** Called when Unity is ready to receive messages. */
1313
onReady?: () => void
14+
15+
/** Sets whether the screen should stay on. */
16+
keepAwake?: boolean
1417
}
1518

1619
export class UnityView extends React.Component<UnityViewProps> {
@@ -24,9 +27,17 @@ export class UnityView extends React.Component<UnityViewProps> {
2427
if (this.props.onReady) {
2528
UnityModule.ensureIsReady(this.props.onReady)
2629
}
30+
31+
if (this.props.keepAwake) {
32+
UnityModule.setKeepAwake(this.props.keepAwake)
33+
}
2734
}
2835

2936
componentWillUnmount() {
37+
if (this.props.keepAwake) {
38+
UnityModule.setKeepAwake(false)
39+
}
40+
3041
this.listener?.remove()
3142
}
3243

0 commit comments

Comments
 (0)