Skip to content

Commit 93d2b44

Browse files
committed
fix: add custom expo plugin in expo sample app
1 parent 05892b8 commit 93d2b44

File tree

2 files changed

+80
-1
lines changed

2 files changed

+80
-1
lines changed

examples/ExpoMessaging/app.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -62,7 +62,8 @@
6262
{
6363
"microphonePermission": "$(PRODUCT_NAME) would like to use your microphone for voice recording."
6464
}
65-
]
65+
],
66+
"./plugins/keyboardInsetMainActivityListener.js"
6667
]
6768
}
6869
}
Lines changed: 78 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,78 @@
1+
const { withMainActivity, createRunOncePlugin } = require('@expo/config-plugins');
2+
3+
const requiredImports = [
4+
'import android.os.Build',
5+
'import android.os.Bundle',
6+
'import android.view.View',
7+
'import androidx.core.view.ViewCompat',
8+
'import androidx.core.view.WindowInsetsCompat',
9+
'import androidx.core.view.updatePadding',
10+
];
11+
12+
const customInsetHandler = `
13+
if (Build.VERSION.SDK_INT >= 35) {
14+
val rootView = findViewById<View>(android.R.id.content)
15+
16+
ViewCompat.setOnApplyWindowInsetsListener(rootView) { view, insets ->
17+
val bars = insets.getInsets(
18+
WindowInsetsCompat.Type.systemBars()
19+
or WindowInsetsCompat.Type.displayCutout()
20+
or WindowInsetsCompat.Type.ime()
21+
)
22+
rootView.updatePadding(
23+
left = bars.left,
24+
top = bars.top,
25+
right = bars.right,
26+
bottom = bars.bottom
27+
)
28+
WindowInsetsCompat.CONSUMED
29+
}
30+
}
31+
`;
32+
33+
const withCustomMainActivity = (config) => {
34+
return withMainActivity(config, (mod) => {
35+
if (mod.modResults.language !== 'kt') {
36+
throw new Error('MainActivity must be written in Kotlin for this plugin.');
37+
}
38+
39+
let contents = mod.modResults.contents;
40+
41+
// Add missing imports
42+
const packageLineMatch = contents.match(/^package\s+[^\n]+\n/);
43+
if (packageLineMatch) {
44+
const packageLine = packageLineMatch[0];
45+
for (const imp of requiredImports) {
46+
if (!contents.includes(imp)) {
47+
contents = contents.replace(packageLine, packageLine + imp + '\n');
48+
}
49+
}
50+
}
51+
52+
// Inject inside onCreate(), right after super.onCreate(null)
53+
// Match the full onCreate method
54+
const onCreateMethodRegex = /override fun onCreate\(savedInstanceState: Bundle\?\) \{([\s\S]*?)^\s*}/m;
55+
56+
// If the method exists and doesn't already contain a custom ViewCompat.setOnApplyWindowInsetsListener, inject it
57+
if (onCreateMethodRegex.test(contents) && !contents.includes('ViewCompat.setOnApplyWindowInsetsListener')) {
58+
contents = contents.replace(onCreateMethodRegex, (match, body) => {
59+
// Inject after super.onCreate(null)
60+
const modifiedBody = body.replace(
61+
/super\.onCreate\(null\);?/,
62+
(superLine) => `${superLine}\n${customInsetHandler}`
63+
);
64+
65+
return `override fun onCreate(savedInstanceState: Bundle?) {\n${modifiedBody}\n}`;
66+
});
67+
}
68+
69+
mod.modResults.contents = contents;
70+
return mod;
71+
});
72+
};
73+
74+
module.exports = createRunOncePlugin(
75+
withCustomMainActivity,
76+
'keyboard-inset-main-activity-listener-plugin',
77+
'0.0.1'
78+
);

0 commit comments

Comments
 (0)