@@ -2,39 +2,23 @@ const path = require("path");
2
2
const fs = require ( "fs" ) ;
3
3
4
4
const androidBasePath = path . join ( __dirname , "../android/app/src/main" ) ;
5
- const javaOrKotlinBasePath = path . join (
5
+ const kotlinBasePath = path . join (
6
6
androidBasePath ,
7
7
"java/com/digitalnomad91/codebuilderadmin"
8
8
) ;
9
9
10
10
const androidManifestPath = path . join ( androidBasePath , "AndroidManifest.xml" ) ;
11
- const mainActivityPathKotlin = path . join (
12
- javaOrKotlinBasePath ,
13
- "MainActivity.kt"
14
- ) ;
15
- const serviceKotlinPath = path . join (
16
- javaOrKotlinBasePath ,
17
- "ScreenRecordService.kt"
18
- ) ;
19
-
20
- // Clean up potential duplicate in old java directory
21
- const oldJavaServicePath = path . join (
22
- androidBasePath ,
23
- "java/com/digitalnomad91/codebuilderadmin/ScreenRecordService.kt"
24
- ) ;
25
- if ( fs . existsSync ( oldJavaServicePath ) ) {
26
- fs . unlinkSync ( oldJavaServicePath ) ;
27
- console . log ( "🧹 Removed duplicate service file from java directory" ) ;
28
- }
11
+ const mainActivityPath = path . join ( kotlinBasePath , "MainActivity.kt" ) ;
12
+ const servicePath = path . join ( kotlinBasePath , "ScreenRecordService.kt" ) ;
29
13
30
14
const ensurePermissions = ( ) => {
31
15
if ( ! fs . existsSync ( androidManifestPath ) ) {
32
- console . error ( "AndroidManifest.xml not found. " ) ;
16
+ console . error ( "❌ AndroidManifest.xml not found" ) ;
33
17
return ;
34
18
}
35
19
36
20
let manifestContent = fs . readFileSync ( androidManifestPath , "utf8" ) ;
37
- const permissions = [
21
+ const requiredPermissions = [
38
22
"android.permission.RECORD_AUDIO" ,
39
23
"android.permission.FOREGROUND_SERVICE" ,
40
24
"android.permission.SYSTEM_ALERT_WINDOW" ,
@@ -44,148 +28,185 @@ const ensurePermissions = () => {
44
28
] ;
45
29
46
30
let modified = false ;
47
- permissions . forEach ( ( permission ) => {
31
+ requiredPermissions . forEach ( ( permission ) => {
48
32
if ( ! manifestContent . includes ( permission ) ) {
49
33
manifestContent = manifestContent . replace (
50
34
"</manifest>" ,
51
- ` <uses-permission android:name="${ permission } "/>\n</manifest>`
35
+ ` <uses-permission android:name="${ permission } " />\n</manifest>`
52
36
) ;
53
37
modified = true ;
54
38
}
55
39
} ) ;
56
40
57
41
if ( modified ) {
58
42
fs . writeFileSync ( androidManifestPath , manifestContent , "utf8" ) ;
59
- console . log ( "✅ AndroidManifest.xml updated with permissions. " ) ;
43
+ console . log ( "✅ AndroidManifest.xml permissions updated " ) ;
60
44
} else {
61
- console . log ( "✅ AndroidManifest.xml has necessary permissions. " ) ;
45
+ console . log ( "✅ AndroidManifest.xml has required permissions" ) ;
62
46
}
63
47
} ;
64
48
65
49
const ensureMainActivityModifications = ( ) => {
66
- if ( ! fs . existsSync ( mainActivityPathKotlin ) ) {
67
- console . error ( "❌ MainActivity.kt not found. " ) ;
50
+ if ( ! fs . existsSync ( mainActivityPath ) ) {
51
+ console . error ( "❌ MainActivity.kt not found" ) ;
68
52
return ;
69
53
}
70
54
71
- let content = fs . readFileSync ( mainActivityPathKotlin , "utf8" ) ;
55
+ let content = fs . readFileSync ( mainActivityPath , "utf8" ) ;
56
+
57
+ // Clean up duplicate imports
58
+ const importsToManage = [
59
+ "android.os.Bundle" ,
60
+ "android.content.Context" ,
61
+ "android.content.Intent" ,
62
+ "android.media.projection.MediaProjectionManager" ,
63
+ ] ;
64
+
65
+ importsToManage . forEach ( ( imp ) => {
66
+ const importRegex = new RegExp ( `import ${ imp } [\n\r]` , "g" ) ;
67
+ if ( ( content . match ( importRegex ) || [ ] ) . length > 1 ) {
68
+ content = content . replace ( importRegex , "" ) ;
69
+ content = `import ${ imp } \n${ content } ` ;
70
+ }
71
+ } ) ;
72
+
73
+ // Ensure required imports exist
74
+ const requiredImports = `
75
+ import android.os.Bundle
76
+ import android.content.Context
77
+ import android.content.Intent
78
+ import android.media.projection.MediaProjectionManager
79
+ ` . trim ( ) ;
80
+
81
+ if ( ! content . includes ( "MediaProjectionManager" ) ) {
82
+ content = content . replace (
83
+ / i m p o r t c o m \. f a c e b o o k \. r e a c t \. R e a c t A c t i v i t y / ,
84
+ `import com.facebook.react.ReactActivity\n${ requiredImports } `
85
+ ) ;
86
+ }
87
+
88
+ // Injection code with null safety and proper overrides
72
89
const injectionCode = `
73
90
private val SCREEN_RECORD_REQUEST_CODE = 1001
74
- private var projectionManager: MediaProjectionManager? = null
91
+ private lateinit var projectionManager: MediaProjectionManager
75
92
76
93
override fun onCreate(savedInstanceState: Bundle?) {
77
94
super.onCreate(savedInstanceState)
78
95
projectionManager = getSystemService(Context.MEDIA_PROJECTION_SERVICE) as MediaProjectionManager
79
96
}
80
97
81
98
fun startScreenRecording() {
82
- val intent = projectionManager? .createScreenCaptureIntent()
83
- startActivityForResult(intent , SCREEN_RECORD_REQUEST_CODE)
99
+ val captureIntent = projectionManager.createScreenCaptureIntent()
100
+ startActivityForResult(captureIntent , SCREEN_RECORD_REQUEST_CODE)
84
101
}
85
102
86
103
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
87
104
super.onActivityResult(requestCode, resultCode, data)
88
- if (requestCode == SCREEN_RECORD_REQUEST_CODE) {
89
- val serviceIntent = Intent(this, ScreenRecordService::class.java)
90
- serviceIntent.putExtra("RESULT_CODE", resultCode)
91
- serviceIntent.putExtra("DATA", data)
92
- startForegroundService(serviceIntent)
105
+ if (requestCode == SCREEN_RECORD_REQUEST_CODE && data != null) {
106
+ Intent(this, ScreenRecordService::class.java).apply {
107
+ putExtra("RESULT_CODE", resultCode)
108
+ putExtra("DATA", data)
109
+ startForegroundService(this)
110
+ }
93
111
}
94
112
}
95
- ` ;
96
-
97
- // Add imports if missing
98
- if (
99
- ! content . includes ( "import android.media.projection.MediaProjectionManager" )
100
- ) {
101
- content = content . replace (
102
- "import com.facebook.react.ReactActivity" ,
103
- `import com.facebook.react.ReactActivity
104
- import android.content.Context
105
- import android.content.Intent
106
- import android.media.projection.MediaProjectionManager
107
- import android.os.Bundle`
108
- ) ;
109
- }
113
+ ` . trim ( ) ;
110
114
111
115
if ( ! content . includes ( "SCREEN_RECORD_REQUEST_CODE" ) ) {
116
+ // Remove any existing duplicate code
117
+ const duplicateCodePatterns = [
118
+ / p r i v a t e v a l S C R E E N _ R E C O R D _ R E Q U E S T _ C O D E = \d + / ,
119
+ / o v e r r i d e f u n o n C r e a t e \( .* ?\) \s * \{ [ \s \S ] * ?\} / ,
120
+ / f u n s t a r t S c r e e n R e c o r d i n g \( \) \s * \{ [ \s \S ] * ?\} / ,
121
+ / o v e r r i d e f u n o n A c t i v i t y R e s u l t \( .* ?\) \s * \{ [ \s \S ] * ?\} / ,
122
+ ] ;
123
+
124
+ duplicateCodePatterns . forEach ( ( pattern ) => {
125
+ content = content . replace ( pattern , "" ) ;
126
+ } ) ;
127
+
128
+ // Insert new code
112
129
content = content . replace (
113
- / c l a s s M a i n A c t i v i t y : R e a c t A c t i v i t y \( \) \{ / ,
114
- `class MainActivity : ReactActivity() {${ injectionCode } `
130
+ / c l a s s M a i n A c t i v i t y : R e a c t A c t i v i t y \( \) \s * \{ / ,
131
+ `class MainActivity : ReactActivity() {\n ${ injectionCode } \n `
115
132
) ;
116
- fs . writeFileSync ( mainActivityPathKotlin , content , "utf8" ) ;
117
- console . log ( "✅ MainActivity.kt updated." ) ;
133
+
134
+ fs . writeFileSync ( mainActivityPath , content , "utf8" ) ;
135
+ console . log ( "✅ MainActivity.kt updated with proper implementations" ) ;
118
136
} else {
119
- console . log ( "✅ MainActivity already modified. " ) ;
137
+ console . log ( "✅ MainActivity already contains correct code " ) ;
120
138
}
121
139
} ;
122
140
123
141
const ensureScreenRecordService = ( ) => {
124
- const serviceDir = path . dirname ( serviceKotlinPath ) ;
125
- if ( ! fs . existsSync ( serviceDir ) ) {
126
- fs . mkdirSync ( serviceDir , { recursive : true } ) ;
127
- console . log ( "✅ Created service directory" ) ;
142
+ if ( ! fs . existsSync ( kotlinBasePath ) ) {
143
+ fs . mkdirSync ( kotlinBasePath , { recursive : true } ) ;
128
144
}
129
145
130
- if ( ! fs . existsSync ( serviceKotlinPath ) ) {
146
+ if ( ! fs . existsSync ( servicePath ) ) {
131
147
const serviceCode = `package com.digitalnomad91.codebuilderadmin
132
148
133
149
import android.app.Notification
134
150
import android.app.NotificationChannel
135
151
import android.app.NotificationManager
136
152
import android.app.Service
137
153
import android.content.Intent
138
- import android.media.projection.MediaProjection
139
154
import android.os.Build
140
155
import android.os.IBinder
141
156
import androidx.core.app.NotificationCompat
142
157
import com.digitalnomad91.codebuilderadmin.R
143
158
144
159
class ScreenRecordService : Service() {
145
- private val CHANNEL_ID = "ScreenRecordChannel"
146
- private var mediaProjection: MediaProjection? = null
160
+ companion object {
161
+ const val CHANNEL_ID = "ScreenRecorderChannel"
162
+ }
147
163
148
164
override fun onStartCommand(intent: Intent?, flags: Int, startId: Int): Int {
149
- createNotification()
165
+ createNotificationChannel()
166
+ startForeground(1, createNotification())
150
167
return START_STICKY
151
168
}
152
169
153
- private fun createNotification () {
170
+ private fun createNotificationChannel () {
154
171
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
155
172
val channel = NotificationChannel(
156
173
CHANNEL_ID,
157
174
"Screen Recording",
158
175
NotificationManager.IMPORTANCE_LOW
159
- )
160
- val manager = getSystemService(NotificationManager::class.java)
161
- manager.createNotificationChannel(channel)
176
+ ).apply {
177
+ description = "Recording screen activity"
178
+ }
179
+ (getSystemService(NOTIFICATION_SERVICE) as NotificationManager)
180
+ .createNotificationChannel(channel)
162
181
}
182
+ }
163
183
164
- val notification = NotificationCompat.Builder(this, CHANNEL_ID)
184
+ private fun createNotification(): Notification {
185
+ return NotificationCompat.Builder(this, CHANNEL_ID)
165
186
.setContentTitle("Screen Recording")
166
- .setContentText("Your screen is being recorded ")
187
+ .setContentText("Recording in progress ")
167
188
.setSmallIcon(R.mipmap.ic_launcher_foreground)
168
189
.build()
169
-
170
- startForeground(1, notification)
171
190
}
172
191
173
192
override fun onBind(intent: Intent?): IBinder? = null
174
193
}
175
194
` ;
176
- fs . writeFileSync ( serviceKotlinPath , serviceCode , "utf8" ) ;
177
- console . log ( "✅ ScreenRecordService.kt created. " ) ;
195
+ fs . writeFileSync ( servicePath , serviceCode , "utf8" ) ;
196
+ console . log ( "✅ ScreenRecordService.kt created" ) ;
178
197
} else {
179
- console . log ( "✅ ScreenRecordService.kt exists. " ) ;
198
+ console . log ( "✅ ScreenRecordService.kt exists" ) ;
180
199
}
181
200
} ;
182
201
183
- // Execute all steps
202
+ // Execute all steps with error handling
184
203
try {
204
+ console . log ( "\n🚀 Starting screen recording setup..." ) ;
185
205
ensurePermissions ( ) ;
186
206
ensureMainActivityModifications ( ) ;
187
207
ensureScreenRecordService ( ) ;
188
- console . log ( "🎉 Screen recording setup completed! " ) ;
208
+ console . log ( "🎉 Screen recording setup completed successfully!\n " ) ;
189
209
} catch ( error ) {
190
- console . error ( "❌ Setup failed:" , error ) ;
210
+ console . error ( "\n❌ Setup failed:" , error . message ) ;
211
+ process . exit ( 1 ) ;
191
212
}
0 commit comments