Skip to content

Commit 567ec4d

Browse files
authored
fix(plugin): missing intent and configuration imports logic (#61)
1 parent 12323b9 commit 567ec4d

File tree

7 files changed

+264
-14
lines changed

7 files changed

+264
-14
lines changed

README.md

Lines changed: 10 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -50,7 +50,11 @@ You can install the package like any other Expo package, using the following com
5050
npx expo install react-native-orientation-director
5151
```
5252

53-
Then, you need to add the plugin to your app.json file:
53+
## Setup
54+
55+
### Expo
56+
57+
Simply add the library plugin to your `app.json` file:
5458

5559
```json
5660
{
@@ -66,9 +70,9 @@ This way, Expo will handle the native setup for you during `prebuild`.
6670

6771
> Note: only SDK 50 and above are supported, the plugin is configured to handle only the kotlin template.
6872
69-
## Setup
73+
### Bare
7074

71-
### Android
75+
#### Android
7276

7377
This library uses a custom broadcast receiver to handle the manual orientation changes: when the user disables the
7478
autorotation feature and the system prompts the user to rotate the device, the library will listen to the broadcast
@@ -96,12 +100,12 @@ override fun onConfigurationChanged(newConfig: Configuration) {
96100

97101
Nothing else is required for Android.
98102

99-
### iOS
103+
#### iOS
100104

101105
To properly handle interface orientation changes in iOS, you need to update your AppDelegate file. Since React Native
102106
0.77, the AppDelegate has been migrated to Swift, so see the instructions below for both Swift and Objective-C.
103107

104-
#### Objective-C
108+
##### Objective-C
105109

106110
In your AppDelegate.h file, import "OrientationDirector.h" and implement supportedInterfaceOrientationsForWindow method as follows:
107111

@@ -114,7 +118,7 @@ In your AppDelegate.h file, import "OrientationDirector.h" and implement support
114118
}
115119
```
116120

117-
#### Swift
121+
##### Swift
118122

119123
You need to create a [bridging header](https://developer.apple.com/documentation/swift/importing-objective-c-into-swift#Import-Code-Within-an-App-Target)
120124
to import the library, as shown below:

plugin/__tests__/__snapshots__/withRNOrientationMainActivity.spec.ts.snap

Lines changed: 120 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,19 +1,136 @@
11
// Jest Snapshot v1, https://goo.gl/fbAQLP
22

3-
exports[`withRNOrientationMainActivity updates the MainActivity.kt with both import and method implementation 1`] = `
3+
exports[`withRNOrientationMainActivity skips the MainActivity.kt configuration import when it's already set 1`] = `
44
"package com.orientationdirectorexample
55
6-
import android.content.Intent
76
import android.content.res.Configuration
87
import android.os.Bundle
98
import com.facebook.react.ReactActivity
109
import com.facebook.react.ReactActivityDelegate
1110
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
1211
import com.facebook.react.defaults.DefaultReactActivityDelegate
1312
14-
// React Native Orientation Director @generated begin @react-native-orientation-director/library-import - expo prebuild (DO NOT MODIFY) sync-dd77fee7fe624fed474053ea60c3105920a01a6a
13+
// React Native Orientation Director @generated begin @react-native-orientation-director/system-intent-import - expo prebuild (DO NOT MODIFY) sync-e6b9f54e19ab3cfd8689165dc8aa1ae37ba84e44
14+
import android.content.Intent
15+
// React Native Orientation Director @generated end @react-native-orientation-director/system-intent-import
16+
// React Native Orientation Director @generated begin @react-native-orientation-director/library-import - expo prebuild (DO NOT MODIFY) sync-7169e02357214d7bab1282e0a498c9c731ada6ad
1517
import com.orientationdirector.implementation.ConfigurationChangedBroadcastReceiver
18+
// React Native Orientation Director @generated end @react-native-orientation-director/library-import
19+
class MainActivity : ReactActivity() {
20+
21+
/**
22+
* Returns the name of the main component registered from JavaScript. This is used to schedule
23+
* rendering of the component.
24+
*/
25+
override fun getMainComponentName(): String = "OrientationDirectorExample"
26+
27+
/**
28+
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
29+
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
30+
*/
31+
override fun createReactActivityDelegate(): ReactActivityDelegate =
32+
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
33+
34+
override fun onCreate(savedInstanceState: Bundle?) {
35+
super.onCreate(null)
36+
}
37+
// React Native Orientation Director @generated begin @react-native-orientation-director/supportedInterfaceOrientationsFor-implementation - expo prebuild (DO NOT MODIFY) sync-7a5cdf10057b2ddf1bcf4593bf408862cbed5473
38+
39+
override fun onConfigurationChanged(newConfig: Configuration) {
40+
super.onConfigurationChanged(newConfig)
41+
42+
val orientationDirectorCustomAction =
43+
packageName + "." + ConfigurationChangedBroadcastReceiver.CUSTOM_INTENT_ACTION
44+
45+
val intent =
46+
Intent(orientationDirectorCustomAction).apply {
47+
putExtra("newConfig", newConfig)
48+
setPackage(packageName)
49+
}
1650
51+
this.sendBroadcast(intent)
52+
}
53+
54+
// React Native Orientation Director @generated end @react-native-orientation-director/supportedInterfaceOrientationsFor-implementation
55+
56+
}
57+
"
58+
`;
59+
60+
exports[`withRNOrientationMainActivity skips the MainActivity.kt intent import when it's already set 1`] = `
61+
"package com.orientationdirectorexample
62+
63+
import android.content.Intent
64+
import android.os.Bundle
65+
import com.facebook.react.ReactActivity
66+
import com.facebook.react.ReactActivityDelegate
67+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
68+
import com.facebook.react.defaults.DefaultReactActivityDelegate
69+
70+
// React Native Orientation Director @generated begin @react-native-orientation-director/system-configuration-import - expo prebuild (DO NOT MODIFY) sync-e946440a29a0e93549862b7c63f1655b232ef6fb
71+
import android.content.res.Configuration
72+
// React Native Orientation Director @generated end @react-native-orientation-director/system-configuration-import
73+
// React Native Orientation Director @generated begin @react-native-orientation-director/library-import - expo prebuild (DO NOT MODIFY) sync-7169e02357214d7bab1282e0a498c9c731ada6ad
74+
import com.orientationdirector.implementation.ConfigurationChangedBroadcastReceiver
75+
// React Native Orientation Director @generated end @react-native-orientation-director/library-import
76+
class MainActivity : ReactActivity() {
77+
78+
/**
79+
* Returns the name of the main component registered from JavaScript. This is used to schedule
80+
* rendering of the component.
81+
*/
82+
override fun getMainComponentName(): String = "OrientationDirectorExample"
83+
84+
/**
85+
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
86+
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
87+
*/
88+
override fun createReactActivityDelegate(): ReactActivityDelegate =
89+
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
90+
91+
override fun onCreate(savedInstanceState: Bundle?) {
92+
super.onCreate(null)
93+
}
94+
// React Native Orientation Director @generated begin @react-native-orientation-director/supportedInterfaceOrientationsFor-implementation - expo prebuild (DO NOT MODIFY) sync-7a5cdf10057b2ddf1bcf4593bf408862cbed5473
95+
96+
override fun onConfigurationChanged(newConfig: Configuration) {
97+
super.onConfigurationChanged(newConfig)
98+
99+
val orientationDirectorCustomAction =
100+
packageName + "." + ConfigurationChangedBroadcastReceiver.CUSTOM_INTENT_ACTION
101+
102+
val intent =
103+
Intent(orientationDirectorCustomAction).apply {
104+
putExtra("newConfig", newConfig)
105+
setPackage(packageName)
106+
}
107+
108+
this.sendBroadcast(intent)
109+
}
110+
111+
// React Native Orientation Director @generated end @react-native-orientation-director/supportedInterfaceOrientationsFor-implementation
112+
113+
}
114+
"
115+
`;
116+
117+
exports[`withRNOrientationMainActivity updates the MainActivity.kt with both imports and method implementation 1`] = `
118+
"package com.orientationdirectorexample
119+
120+
import android.os.Bundle
121+
import com.facebook.react.ReactActivity
122+
import com.facebook.react.ReactActivityDelegate
123+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
124+
import com.facebook.react.defaults.DefaultReactActivityDelegate
125+
126+
// React Native Orientation Director @generated begin @react-native-orientation-director/system-intent-import - expo prebuild (DO NOT MODIFY) sync-e6b9f54e19ab3cfd8689165dc8aa1ae37ba84e44
127+
import android.content.Intent
128+
// React Native Orientation Director @generated end @react-native-orientation-director/system-intent-import
129+
// React Native Orientation Director @generated begin @react-native-orientation-director/system-configuration-import - expo prebuild (DO NOT MODIFY) sync-e946440a29a0e93549862b7c63f1655b232ef6fb
130+
import android.content.res.Configuration
131+
// React Native Orientation Director @generated end @react-native-orientation-director/system-configuration-import
132+
// React Native Orientation Director @generated begin @react-native-orientation-director/library-import - expo prebuild (DO NOT MODIFY) sync-7169e02357214d7bab1282e0a498c9c731ada6ad
133+
import com.orientationdirector.implementation.ConfigurationChangedBroadcastReceiver
17134
// React Native Orientation Director @generated end @react-native-orientation-director/library-import
18135
class MainActivity : ReactActivity() {
19136

plugin/__tests__/fixtures/MainActivity.kt

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
package com.orientationdirectorexample
22

3-
import android.content.Intent
4-
import android.content.res.Configuration
53
import android.os.Bundle
64
import com.facebook.react.ReactActivity
75
import com.facebook.react.ReactActivityDelegate
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.orientationdirectorexample
2+
3+
import android.content.res.Configuration
4+
import android.os.Bundle
5+
import com.facebook.react.ReactActivity
6+
import com.facebook.react.ReactActivityDelegate
7+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
8+
import com.facebook.react.defaults.DefaultReactActivityDelegate
9+
10+
class MainActivity : ReactActivity() {
11+
12+
/**
13+
* Returns the name of the main component registered from JavaScript. This is used to schedule
14+
* rendering of the component.
15+
*/
16+
override fun getMainComponentName(): String = "OrientationDirectorExample"
17+
18+
/**
19+
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
20+
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
21+
*/
22+
override fun createReactActivityDelegate(): ReactActivityDelegate =
23+
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
24+
25+
override fun onCreate(savedInstanceState: Bundle?) {
26+
super.onCreate(null)
27+
}
28+
29+
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
package com.orientationdirectorexample
2+
3+
import android.content.Intent
4+
import android.os.Bundle
5+
import com.facebook.react.ReactActivity
6+
import com.facebook.react.ReactActivityDelegate
7+
import com.facebook.react.defaults.DefaultNewArchitectureEntryPoint.fabricEnabled
8+
import com.facebook.react.defaults.DefaultReactActivityDelegate
9+
10+
class MainActivity : ReactActivity() {
11+
12+
/**
13+
* Returns the name of the main component registered from JavaScript. This is used to schedule
14+
* rendering of the component.
15+
*/
16+
override fun getMainComponentName(): String = "OrientationDirectorExample"
17+
18+
/**
19+
* Returns the instance of the [ReactActivityDelegate]. We use [DefaultReactActivityDelegate]
20+
* which allows you to enable New Architecture with a single boolean flags [fabricEnabled]
21+
*/
22+
override fun createReactActivityDelegate(): ReactActivityDelegate =
23+
DefaultReactActivityDelegate(this, mainComponentName, fabricEnabled)
24+
25+
override fun onCreate(savedInstanceState: Bundle?) {
26+
super.onCreate(null)
27+
}
28+
29+
}

plugin/__tests__/withRNOrientationMainActivity.spec.ts

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8,11 +8,33 @@ describe('withRNOrientationMainActivity', function () {
88
jest.resetAllMocks();
99
});
1010

11-
it('updates the MainActivity.kt with both import and method implementation', async function () {
11+
it('updates the MainActivity.kt with both imports and method implementation', async function () {
1212
const mainActivityPath = path.join(__dirname, './fixtures/MainActivity.kt');
1313
const mainActivity = await fs.promises.readFile(mainActivityPath, 'utf-8');
1414

1515
const result = ktFileUpdater(mainActivity);
1616
expect(result).toMatchSnapshot();
1717
});
18+
19+
it("skips the MainActivity.kt intent import when it's already set", async function () {
20+
const mainActivityPath = path.join(
21+
__dirname,
22+
'./fixtures/MainActivityWithIntentImport.kt'
23+
);
24+
const mainActivity = await fs.promises.readFile(mainActivityPath, 'utf-8');
25+
26+
const result = ktFileUpdater(mainActivity);
27+
expect(result).toMatchSnapshot();
28+
});
29+
30+
it("skips the MainActivity.kt configuration import when it's already set", async function () {
31+
const mainActivityPath = path.join(
32+
__dirname,
33+
'./fixtures/MainActivityWithConfigurationImport.kt'
34+
);
35+
const mainActivity = await fs.promises.readFile(mainActivityPath, 'utf-8');
36+
37+
const result = ktFileUpdater(mainActivity);
38+
expect(result).toMatchSnapshot();
39+
});
1840
});

plugin/src/withRNOrientationMainActivity.ts

Lines changed: 53 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -35,13 +35,16 @@ function getCompatibleFileUpdater(
3535
}
3636

3737
export function ktFileUpdater(originalContents: string): string {
38+
const systemImportsContents =
39+
updateContentsWithSystemImports(originalContents);
40+
3841
const libraryImportCodeBlock =
39-
'import com.orientationdirector.implementation.ConfigurationChangedBroadcastReceiver\n';
42+
'import com.orientationdirector.implementation.ConfigurationChangedBroadcastReceiver';
4043
const rightBeforeClassDeclaration = /class MainActivity/g;
4144

4245
const importMergeResults = mergeContents({
4346
tag: '@react-native-orientation-director/library-import',
44-
src: originalContents,
47+
src: systemImportsContents,
4548
newSrc: libraryImportCodeBlock,
4649
anchor: rightBeforeClassDeclaration,
4750
offset: 0,
@@ -78,3 +81,51 @@ export function ktFileUpdater(originalContents: string): string {
7881

7982
return implementationMergeResults.contents;
8083
}
84+
85+
function updateContentsWithSystemImports(originalContents: string) {
86+
const rightBeforeClassDeclaration = /class MainActivity/g;
87+
88+
let possibleUpdatedContents = originalContents;
89+
possibleUpdatedContents = addIntentImportIfNecessary(possibleUpdatedContents);
90+
possibleUpdatedContents = addConfigurationImportIfNecessary(
91+
possibleUpdatedContents
92+
);
93+
94+
return possibleUpdatedContents;
95+
96+
function addIntentImportIfNecessary(_contents: string) {
97+
const systemIntentImportCodeBlock = 'import android.content.Intent';
98+
if (_contents.includes(systemIntentImportCodeBlock)) {
99+
return _contents;
100+
}
101+
102+
const mergeResults = mergeContents({
103+
tag: '@react-native-orientation-director/system-intent-import',
104+
src: _contents,
105+
newSrc: systemIntentImportCodeBlock,
106+
anchor: rightBeforeClassDeclaration,
107+
offset: 0,
108+
comment: '// React Native Orientation Director',
109+
});
110+
111+
return mergeResults.contents;
112+
}
113+
function addConfigurationImportIfNecessary(_contents: string) {
114+
const systemConfigurationImportCodeBlock =
115+
'import android.content.res.Configuration';
116+
if (possibleUpdatedContents.includes(systemConfigurationImportCodeBlock)) {
117+
return _contents;
118+
}
119+
120+
const mergeResults = mergeContents({
121+
tag: '@react-native-orientation-director/system-configuration-import',
122+
src: possibleUpdatedContents,
123+
newSrc: systemConfigurationImportCodeBlock,
124+
anchor: rightBeforeClassDeclaration,
125+
offset: 0,
126+
comment: '// React Native Orientation Director',
127+
});
128+
129+
return mergeResults.contents;
130+
}
131+
}

0 commit comments

Comments
 (0)