@capgo/capacitor-screen-recorder 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CapacitorScreenRecorder.podspec +17 -0
- package/README.md +53 -0
- package/android/build.gradle +64 -0
- package/android/src/main/AndroidManifest.xml +3 -0
- package/android/src/main/java/ee/forgr/plugin/screenrecorder/ScreenRecorderPlugin.java +33 -0
- package/android/src/main/res/.gitkeep +0 -0
- package/dist/docs.json +33 -0
- package/dist/esm/definitions.d.ts +12 -0
- package/dist/esm/definitions.js +2 -0
- package/dist/esm/definitions.js.map +1 -0
- package/dist/esm/index.d.ts +4 -0
- package/dist/esm/index.js +7 -0
- package/dist/esm/index.js.map +1 -0
- package/dist/esm/web.d.ts +6 -0
- package/dist/esm/web.js +10 -0
- package/dist/esm/web.js.map +1 -0
- package/dist/plugin.cjs.js +26 -0
- package/dist/plugin.cjs.js.map +1 -0
- package/dist/plugin.js +29 -0
- package/dist/plugin.js.map +1 -0
- package/ios/Plugin/Info.plist +24 -0
- package/ios/Plugin/ScreenRecorderPlugin.h +10 -0
- package/ios/Plugin/ScreenRecorderPlugin.m +9 -0
- package/ios/Plugin/ScreenRecorderPlugin.swift +32 -0
- package/ios/Plugin/Wyler.swift +206 -0
- package/package.json +78 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
require 'json'
|
|
2
|
+
|
|
3
|
+
package = JSON.parse(File.read(File.join(__dir__, 'package.json')))
|
|
4
|
+
|
|
5
|
+
Pod::Spec.new do |s|
|
|
6
|
+
s.name = 'CapacitorScreenRecorder'
|
|
7
|
+
s.version = package['version']
|
|
8
|
+
s.summary = package['description']
|
|
9
|
+
s.license = package['license']
|
|
10
|
+
s.homepage = package['repository']['url']
|
|
11
|
+
s.author = package['author']
|
|
12
|
+
s.source = { :git => package['repository']['url'], :tag => s.version.to_s }
|
|
13
|
+
s.source_files = 'ios/Plugin/**/*.{swift,h,m,c,cc,mm,cpp}'
|
|
14
|
+
s.ios.deployment_target = '12.0'
|
|
15
|
+
s.dependency 'Capacitor'
|
|
16
|
+
s.swift_version = '5.1'
|
|
17
|
+
end
|
package/README.md
ADDED
|
@@ -0,0 +1,53 @@
|
|
|
1
|
+
# capacitor-screen-recorder
|
|
2
|
+
|
|
3
|
+
Record device's screen
|
|
4
|
+
|
|
5
|
+
## Install
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install @capgo/capacitor-screen-recorder
|
|
9
|
+
npx cap sync
|
|
10
|
+
```
|
|
11
|
+
|
|
12
|
+
## IOS
|
|
13
|
+
|
|
14
|
+
Nothing special
|
|
15
|
+
|
|
16
|
+
## Android
|
|
17
|
+
|
|
18
|
+
increase project's minSdk version to at least 23.
|
|
19
|
+
|
|
20
|
+
## API
|
|
21
|
+
|
|
22
|
+
<docgen-index>
|
|
23
|
+
|
|
24
|
+
* [`start()`](#start)
|
|
25
|
+
* [`stop()`](#stop)
|
|
26
|
+
|
|
27
|
+
</docgen-index>
|
|
28
|
+
|
|
29
|
+
<docgen-api>
|
|
30
|
+
<!--Update the source file JSDoc comments and rerun docgen to update the docs below-->
|
|
31
|
+
|
|
32
|
+
### start()
|
|
33
|
+
|
|
34
|
+
```typescript
|
|
35
|
+
start() => Promise<void>
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
start the recording
|
|
39
|
+
|
|
40
|
+
--------------------
|
|
41
|
+
|
|
42
|
+
|
|
43
|
+
### stop()
|
|
44
|
+
|
|
45
|
+
```typescript
|
|
46
|
+
stop() => Promise<void>
|
|
47
|
+
```
|
|
48
|
+
|
|
49
|
+
stop the recording
|
|
50
|
+
|
|
51
|
+
--------------------
|
|
52
|
+
|
|
53
|
+
</docgen-api>
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
ext {
|
|
2
|
+
junitVersion = project.hasProperty('junitVersion') ? rootProject.ext.junitVersion : '4.13.1'
|
|
3
|
+
androidxAppCompatVersion = project.hasProperty('androidxAppCompatVersion') ? rootProject.ext.androidxAppCompatVersion : '1.2.0'
|
|
4
|
+
androidxJunitVersion = project.hasProperty('androidxJunitVersion') ? rootProject.ext.androidxJunitVersion : '1.1.2'
|
|
5
|
+
androidxEspressoCoreVersion = project.hasProperty('androidxEspressoCoreVersion') ? rootProject.ext.androidxEspressoCoreVersion : '3.3.0'
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
buildscript {
|
|
9
|
+
ext.kotlin_version = '1.6.0-RC2'
|
|
10
|
+
repositories {
|
|
11
|
+
google()
|
|
12
|
+
jcenter()
|
|
13
|
+
}
|
|
14
|
+
dependencies {
|
|
15
|
+
classpath 'com.android.tools.build:gradle:4.2.1'
|
|
16
|
+
classpath "org.jetbrains.kotlin:kotlin-gradle-plugin:$kotlin_version"
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
apply plugin: 'com.android.library'
|
|
21
|
+
apply plugin: 'kotlin-android'
|
|
22
|
+
|
|
23
|
+
android {
|
|
24
|
+
compileSdkVersion project.hasProperty('compileSdkVersion') ? rootProject.ext.compileSdkVersion : 30
|
|
25
|
+
defaultConfig {
|
|
26
|
+
minSdkVersion project.hasProperty('minSdkVersion') ? rootProject.ext.minSdkVersion : 21
|
|
27
|
+
targetSdkVersion project.hasProperty('targetSdkVersion') ? rootProject.ext.targetSdkVersion : 30
|
|
28
|
+
versionCode 1
|
|
29
|
+
versionName "1.0"
|
|
30
|
+
testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner"
|
|
31
|
+
}
|
|
32
|
+
buildTypes {
|
|
33
|
+
release {
|
|
34
|
+
minifyEnabled false
|
|
35
|
+
proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro'
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
lintOptions {
|
|
39
|
+
abortOnError false
|
|
40
|
+
}
|
|
41
|
+
compileOptions {
|
|
42
|
+
sourceCompatibility JavaVersion.VERSION_1_8
|
|
43
|
+
targetCompatibility JavaVersion.VERSION_1_8
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
repositories {
|
|
48
|
+
google()
|
|
49
|
+
jcenter()
|
|
50
|
+
mavenCentral()
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
|
|
54
|
+
dependencies {
|
|
55
|
+
implementation fileTree(dir: 'libs', include: ['*.jar'])
|
|
56
|
+
implementation project(':capacitor-android')
|
|
57
|
+
implementation "androidx.appcompat:appcompat:$androidxAppCompatVersion"
|
|
58
|
+
testImplementation "junit:junit:$junitVersion"
|
|
59
|
+
androidTestImplementation "androidx.test.ext:junit:$androidxJunitVersion"
|
|
60
|
+
androidTestImplementation "androidx.test.espresso:espresso-core:$androidxEspressoCoreVersion"
|
|
61
|
+
implementation "androidx.core:core-ktx:+"
|
|
62
|
+
implementation ("dev.bmcreations:scrcast:0.3.0")
|
|
63
|
+
implementation "org.jetbrains.kotlin:kotlin-stdlib-jdk7:$kotlin_version"
|
|
64
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
package ee.forgr.plugin.screenrecorder;
|
|
2
|
+
|
|
3
|
+
import com.getcapacitor.Plugin;
|
|
4
|
+
import com.getcapacitor.PluginCall;
|
|
5
|
+
import com.getcapacitor.PluginMethod;
|
|
6
|
+
import com.getcapacitor.annotation.CapacitorPlugin;
|
|
7
|
+
import dev.bmcreations.scrcast.ScrCast;
|
|
8
|
+
import dev.bmcreations.scrcast.config.Options;
|
|
9
|
+
|
|
10
|
+
@CapacitorPlugin(name = "ScreenRecorder")
|
|
11
|
+
public class ScreenRecorderPlugin extends Plugin {
|
|
12
|
+
|
|
13
|
+
private ScrCast recorder;
|
|
14
|
+
|
|
15
|
+
@Override
|
|
16
|
+
public void load() {
|
|
17
|
+
recorder = ScrCast.use(this.bridge.getActivity());
|
|
18
|
+
Options options = new Options();
|
|
19
|
+
recorder.updateOptions(options);
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
@PluginMethod
|
|
23
|
+
public void start(PluginCall call) {
|
|
24
|
+
recorder.record();
|
|
25
|
+
call.resolve();
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@PluginMethod
|
|
29
|
+
public void stop(PluginCall call) {
|
|
30
|
+
recorder.stopRecording();
|
|
31
|
+
call.resolve();
|
|
32
|
+
}
|
|
33
|
+
}
|
|
File without changes
|
package/dist/docs.json
ADDED
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
{
|
|
2
|
+
"api": {
|
|
3
|
+
"name": "ScreenRecorderPlugin",
|
|
4
|
+
"slug": "screenrecorderplugin",
|
|
5
|
+
"docs": "",
|
|
6
|
+
"tags": [],
|
|
7
|
+
"methods": [
|
|
8
|
+
{
|
|
9
|
+
"name": "start",
|
|
10
|
+
"signature": "() => Promise<void>",
|
|
11
|
+
"parameters": [],
|
|
12
|
+
"returns": "Promise<void>",
|
|
13
|
+
"tags": [],
|
|
14
|
+
"docs": "start the recording",
|
|
15
|
+
"complexTypes": [],
|
|
16
|
+
"slug": "start"
|
|
17
|
+
},
|
|
18
|
+
{
|
|
19
|
+
"name": "stop",
|
|
20
|
+
"signature": "() => Promise<void>",
|
|
21
|
+
"parameters": [],
|
|
22
|
+
"returns": "Promise<void>",
|
|
23
|
+
"tags": [],
|
|
24
|
+
"docs": "stop the recording",
|
|
25
|
+
"complexTypes": [],
|
|
26
|
+
"slug": "stop"
|
|
27
|
+
}
|
|
28
|
+
],
|
|
29
|
+
"properties": []
|
|
30
|
+
},
|
|
31
|
+
"interfaces": [],
|
|
32
|
+
"enums": []
|
|
33
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"definitions.js","sourceRoot":"","sources":["../../src/definitions.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { registerPlugin } from '@capacitor/core';
|
|
2
|
+
const ScreenRecorder = registerPlugin('ScreenRecorder', {
|
|
3
|
+
web: () => import('./web').then(m => new m.ScreenRecorderWeb()),
|
|
4
|
+
});
|
|
5
|
+
export * from './definitions';
|
|
6
|
+
export { ScreenRecorder };
|
|
7
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAIjD,MAAM,cAAc,GAAG,cAAc,CAAuB,gBAAgB,EAAE;IAC5E,GAAG,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;CAChE,CAAC,CAAC;AAEH,cAAc,eAAe,CAAC;AAC9B,OAAO,EAAE,cAAc,EAAE,CAAC"}
|
package/dist/esm/web.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { WebPlugin } from '@capacitor/core';
|
|
2
|
+
export class ScreenRecorderWeb extends WebPlugin {
|
|
3
|
+
async start() {
|
|
4
|
+
throw new Error("Method not implemented.");
|
|
5
|
+
}
|
|
6
|
+
async stop() {
|
|
7
|
+
throw new Error("Method not implemented.");
|
|
8
|
+
}
|
|
9
|
+
}
|
|
10
|
+
//# sourceMappingURL=web.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"web.js","sourceRoot":"","sources":["../../src/web.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AAI5C,MAAM,OAAO,iBACX,SAAQ,SAAS;IAEjB,KAAK,CAAC,KAAK;QACP,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;IACD,KAAK,CAAC,IAAI;QACN,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IAC/C,CAAC;CACF"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
4
|
+
|
|
5
|
+
var core = require('@capacitor/core');
|
|
6
|
+
|
|
7
|
+
const ScreenRecorder = core.registerPlugin('ScreenRecorder', {
|
|
8
|
+
web: () => Promise.resolve().then(function () { return web; }).then(m => new m.ScreenRecorderWeb()),
|
|
9
|
+
});
|
|
10
|
+
|
|
11
|
+
class ScreenRecorderWeb extends core.WebPlugin {
|
|
12
|
+
async start() {
|
|
13
|
+
throw new Error("Method not implemented.");
|
|
14
|
+
}
|
|
15
|
+
async stop() {
|
|
16
|
+
throw new Error("Method not implemented.");
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
21
|
+
__proto__: null,
|
|
22
|
+
ScreenRecorderWeb: ScreenRecorderWeb
|
|
23
|
+
});
|
|
24
|
+
|
|
25
|
+
exports.ScreenRecorder = ScreenRecorder;
|
|
26
|
+
//# sourceMappingURL=plugin.cjs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.cjs.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst ScreenRecorder = registerPlugin('ScreenRecorder', {\n web: () => import('./web').then(m => new m.ScreenRecorderWeb()),\n});\nexport * from './definitions';\nexport { ScreenRecorder };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ScreenRecorderWeb extends WebPlugin {\n async start() {\n throw new Error(\"Method not implemented.\");\n }\n async stop() {\n throw new Error(\"Method not implemented.\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;;;;AACK,MAAC,cAAc,GAAGA,mBAAc,CAAC,gBAAgB,EAAE;AACxD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;AACnE,CAAC;;ACFM,MAAM,iBAAiB,SAASC,cAAS,CAAC;AACjD,IAAI,MAAM,KAAK,GAAG;AAClB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;AACnD,KAAK;AACL,IAAI,MAAM,IAAI,GAAG;AACjB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;AACnD,KAAK;AACL;;;;;;;;;"}
|
package/dist/plugin.js
ADDED
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
var capacitorScreenRecorder = (function (exports, core) {
|
|
2
|
+
'use strict';
|
|
3
|
+
|
|
4
|
+
const ScreenRecorder = core.registerPlugin('ScreenRecorder', {
|
|
5
|
+
web: () => Promise.resolve().then(function () { return web; }).then(m => new m.ScreenRecorderWeb()),
|
|
6
|
+
});
|
|
7
|
+
|
|
8
|
+
class ScreenRecorderWeb extends core.WebPlugin {
|
|
9
|
+
async start() {
|
|
10
|
+
throw new Error("Method not implemented.");
|
|
11
|
+
}
|
|
12
|
+
async stop() {
|
|
13
|
+
throw new Error("Method not implemented.");
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
var web = /*#__PURE__*/Object.freeze({
|
|
18
|
+
__proto__: null,
|
|
19
|
+
ScreenRecorderWeb: ScreenRecorderWeb
|
|
20
|
+
});
|
|
21
|
+
|
|
22
|
+
exports.ScreenRecorder = ScreenRecorder;
|
|
23
|
+
|
|
24
|
+
Object.defineProperty(exports, '__esModule', { value: true });
|
|
25
|
+
|
|
26
|
+
return exports;
|
|
27
|
+
|
|
28
|
+
})({}, capacitorExports);
|
|
29
|
+
//# sourceMappingURL=plugin.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plugin.js","sources":["esm/index.js","esm/web.js"],"sourcesContent":["import { registerPlugin } from '@capacitor/core';\nconst ScreenRecorder = registerPlugin('ScreenRecorder', {\n web: () => import('./web').then(m => new m.ScreenRecorderWeb()),\n});\nexport * from './definitions';\nexport { ScreenRecorder };\n//# sourceMappingURL=index.js.map","import { WebPlugin } from '@capacitor/core';\nexport class ScreenRecorderWeb extends WebPlugin {\n async start() {\n throw new Error(\"Method not implemented.\");\n }\n async stop() {\n throw new Error(\"Method not implemented.\");\n }\n}\n//# sourceMappingURL=web.js.map"],"names":["registerPlugin","WebPlugin"],"mappings":";;;AACK,UAAC,cAAc,GAAGA,mBAAc,CAAC,gBAAgB,EAAE;IACxD,IAAI,GAAG,EAAE,MAAM,mDAAe,CAAC,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,iBAAiB,EAAE,CAAC;IACnE,CAAC;;ICFM,MAAM,iBAAiB,SAASC,cAAS,CAAC;IACjD,IAAI,MAAM,KAAK,GAAG;IAClB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACnD,KAAK;IACL,IAAI,MAAM,IAAI,GAAG;IACjB,QAAQ,MAAM,IAAI,KAAK,CAAC,yBAAyB,CAAC,CAAC;IACnD,KAAK;IACL;;;;;;;;;;;;;;;;;"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
<?xml version="1.0" encoding="UTF-8"?>
|
|
2
|
+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
|
3
|
+
<plist version="1.0">
|
|
4
|
+
<dict>
|
|
5
|
+
<key>CFBundleDevelopmentRegion</key>
|
|
6
|
+
<string>$(DEVELOPMENT_LANGUAGE)</string>
|
|
7
|
+
<key>CFBundleExecutable</key>
|
|
8
|
+
<string>$(EXECUTABLE_NAME)</string>
|
|
9
|
+
<key>CFBundleIdentifier</key>
|
|
10
|
+
<string>$(PRODUCT_BUNDLE_IDENTIFIER)</string>
|
|
11
|
+
<key>CFBundleInfoDictionaryVersion</key>
|
|
12
|
+
<string>6.0</string>
|
|
13
|
+
<key>CFBundleName</key>
|
|
14
|
+
<string>$(PRODUCT_NAME)</string>
|
|
15
|
+
<key>CFBundlePackageType</key>
|
|
16
|
+
<string>FMWK</string>
|
|
17
|
+
<key>CFBundleShortVersionString</key>
|
|
18
|
+
<string>1.0</string>
|
|
19
|
+
<key>CFBundleVersion</key>
|
|
20
|
+
<string>$(CURRENT_PROJECT_VERSION)</string>
|
|
21
|
+
<key>NSPrincipalClass</key>
|
|
22
|
+
<string></string>
|
|
23
|
+
</dict>
|
|
24
|
+
</plist>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
#import <UIKit/UIKit.h>
|
|
2
|
+
|
|
3
|
+
//! Project version number for Plugin.
|
|
4
|
+
FOUNDATION_EXPORT double PluginVersionNumber;
|
|
5
|
+
|
|
6
|
+
//! Project version string for Plugin.
|
|
7
|
+
FOUNDATION_EXPORT const unsigned char PluginVersionString[];
|
|
8
|
+
|
|
9
|
+
// In this header, you should import all the public headers of your framework using statements like #import <Plugin/PublicHeader.h>
|
|
10
|
+
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#import <Foundation/Foundation.h>
|
|
2
|
+
#import <Capacitor/Capacitor.h>
|
|
3
|
+
|
|
4
|
+
// Define the plugin using the CAP_PLUGIN Macro, and
|
|
5
|
+
// each method the plugin supports using the CAP_PLUGIN_METHOD macro.
|
|
6
|
+
CAP_PLUGIN(ScreenRecorderPlugin, "ScreenRecorder",
|
|
7
|
+
CAP_PLUGIN_METHOD(start, CAPPluginReturnPromise);
|
|
8
|
+
CAP_PLUGIN_METHOD(stop, CAPPluginReturnPromise);
|
|
9
|
+
)
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import Foundation
|
|
2
|
+
import Capacitor
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Please read the Capacitor iOS Plugin Development Guide
|
|
6
|
+
* here: https://capacitorjs.com/docs/plugins/ios
|
|
7
|
+
*/
|
|
8
|
+
@objc(ScreenRecorderPlugin)
|
|
9
|
+
public class ScreenRecorderPlugin: CAPPlugin {
|
|
10
|
+
private let implementation = ScreenRecorder()
|
|
11
|
+
|
|
12
|
+
@objc func start(_ call: CAPPluginCall) {
|
|
13
|
+
implementation.startRecording(saveToCameraRoll: true, handler: { error in
|
|
14
|
+
if let error = error {
|
|
15
|
+
debugPrint("Error when start recording \(error)")
|
|
16
|
+
call.reject("Cannot start recording")
|
|
17
|
+
} else {
|
|
18
|
+
call.resolve()
|
|
19
|
+
}
|
|
20
|
+
})
|
|
21
|
+
}
|
|
22
|
+
@objc func stop(_ call: CAPPluginCall) {
|
|
23
|
+
implementation.stoprecording(handler: { error in
|
|
24
|
+
if let error = error {
|
|
25
|
+
debugPrint("Error when stop recording \(error)")
|
|
26
|
+
call.reject("Cannot stop recording")
|
|
27
|
+
} else {
|
|
28
|
+
call.resolve()
|
|
29
|
+
}
|
|
30
|
+
})
|
|
31
|
+
}
|
|
32
|
+
}
|
|
@@ -0,0 +1,206 @@
|
|
|
1
|
+
//
|
|
2
|
+
// ScreenRecorder.swift
|
|
3
|
+
// Wyler
|
|
4
|
+
//
|
|
5
|
+
// Created by Cesar Vargas on 10.04.20.
|
|
6
|
+
// Copyright © 2020 Cesar Vargas. All rights reserved.
|
|
7
|
+
//
|
|
8
|
+
|
|
9
|
+
import Foundation
|
|
10
|
+
import ReplayKit
|
|
11
|
+
import Photos
|
|
12
|
+
|
|
13
|
+
public enum ScreenRecorderError: Error {
|
|
14
|
+
case notAvailable
|
|
15
|
+
case photoLibraryAccessNotGranted
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
final public class ScreenRecorder {
|
|
19
|
+
private var videoOutputURL: URL?
|
|
20
|
+
private var videoWriter: AVAssetWriter?
|
|
21
|
+
private var videoWriterInput: AVAssetWriterInput?
|
|
22
|
+
private var micAudioWriterInput: AVAssetWriterInput?
|
|
23
|
+
private var appAudioWriterInput: AVAssetWriterInput?
|
|
24
|
+
private var saveToCameraRoll = false
|
|
25
|
+
let recorder = RPScreenRecorder.shared()
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
Starts recording the content of the application screen. It works together with stopRecording
|
|
29
|
+
|
|
30
|
+
- Parameter outputURL: The output where the video will be saved. If nil, it saves it in the documents directory.
|
|
31
|
+
- Parameter size: The size of the video. If nil, it will use the app screen size.
|
|
32
|
+
- Parameter saveToCameraRoll: Whether to save it to camera roll. False by default.
|
|
33
|
+
- Parameter errorHandler: Called when an error is found
|
|
34
|
+
*/
|
|
35
|
+
public func startRecording(to outputURL: URL? = nil,
|
|
36
|
+
size: CGSize? = nil,
|
|
37
|
+
saveToCameraRoll: Bool = false,
|
|
38
|
+
handler: @escaping (Error?) -> Void) {
|
|
39
|
+
recorder.isMicrophoneEnabled = true
|
|
40
|
+
do {
|
|
41
|
+
try createVideoWriter(in: outputURL)
|
|
42
|
+
addVideoWriterInput(size: size)
|
|
43
|
+
self.micAudioWriterInput = createAndAddAudioInput()
|
|
44
|
+
self.appAudioWriterInput = createAndAddAudioInput()
|
|
45
|
+
startCapture(handler: handler)
|
|
46
|
+
} catch let err {
|
|
47
|
+
handler(err)
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
private func checkPhotoLibraryAuthorizationStatus() {
|
|
52
|
+
let status = PHPhotoLibrary.authorizationStatus()
|
|
53
|
+
if status == .notDetermined {
|
|
54
|
+
PHPhotoLibrary.requestAuthorization({ _ in })
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
private func createVideoWriter(in outputURL: URL? = nil) throws {
|
|
59
|
+
let newVideoOutputURL: URL
|
|
60
|
+
|
|
61
|
+
if let passedVideoOutput = outputURL {
|
|
62
|
+
self.videoOutputURL = passedVideoOutput
|
|
63
|
+
newVideoOutputURL = passedVideoOutput
|
|
64
|
+
} else {
|
|
65
|
+
let documentsPath = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true)[0] as NSString
|
|
66
|
+
newVideoOutputURL = URL(fileURLWithPath: documentsPath.appendingPathComponent("WylerNewVideo.mp4"))
|
|
67
|
+
self.videoOutputURL = newVideoOutputURL
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
do {
|
|
71
|
+
try FileManager.default.removeItem(at: newVideoOutputURL)
|
|
72
|
+
} catch {}
|
|
73
|
+
|
|
74
|
+
do {
|
|
75
|
+
try videoWriter = AVAssetWriter(outputURL: newVideoOutputURL, fileType: AVFileType.mp4)
|
|
76
|
+
} catch let writerError as NSError {
|
|
77
|
+
videoWriter = nil
|
|
78
|
+
throw writerError
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
private func addVideoWriterInput(size: CGSize?) {
|
|
83
|
+
let passingSize: CGSize = size ?? UIScreen.main.bounds.size
|
|
84
|
+
|
|
85
|
+
let videoSettings: [String: Any] = [AVVideoCodecKey: AVVideoCodecType.h264,
|
|
86
|
+
AVVideoWidthKey: passingSize.width,
|
|
87
|
+
AVVideoHeightKey: passingSize.height]
|
|
88
|
+
|
|
89
|
+
let newVideoWriterInput = AVAssetWriterInput(mediaType: AVMediaType.video, outputSettings: videoSettings)
|
|
90
|
+
self.videoWriterInput = newVideoWriterInput
|
|
91
|
+
newVideoWriterInput.expectsMediaDataInRealTime = true
|
|
92
|
+
videoWriter?.add(newVideoWriterInput)
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
private func createAndAddAudioInput() -> AVAssetWriterInput {
|
|
96
|
+
let settings = [
|
|
97
|
+
AVFormatIDKey: Int(kAudioFormatMPEG4AAC),
|
|
98
|
+
AVSampleRateKey: 12000,
|
|
99
|
+
AVNumberOfChannelsKey: 1,
|
|
100
|
+
AVEncoderAudioQualityKey: AVAudioQuality.high.rawValue
|
|
101
|
+
]
|
|
102
|
+
|
|
103
|
+
let audioInput = AVAssetWriterInput(mediaType: .audio, outputSettings: settings)
|
|
104
|
+
|
|
105
|
+
audioInput.expectsMediaDataInRealTime = true
|
|
106
|
+
videoWriter?.add(audioInput)
|
|
107
|
+
|
|
108
|
+
return audioInput
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
private func startCapture(handler: @escaping (Error?) -> Void) {
|
|
112
|
+
guard recorder.isAvailable else {
|
|
113
|
+
return handler(ScreenRecorderError.notAvailable)
|
|
114
|
+
}
|
|
115
|
+
var sent = false
|
|
116
|
+
recorder.startCapture(handler: { (sampleBuffer, sampleType, passedError) in
|
|
117
|
+
if let passedError = passedError {
|
|
118
|
+
if (!sent) {
|
|
119
|
+
handler(passedError)
|
|
120
|
+
sent = true
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
switch sampleType {
|
|
125
|
+
case .video:
|
|
126
|
+
self.handleSampleBuffer(sampleBuffer: sampleBuffer)
|
|
127
|
+
case .audioApp:
|
|
128
|
+
self.add(sample: sampleBuffer, to: self.appAudioWriterInput)
|
|
129
|
+
case .audioMic:
|
|
130
|
+
self.add(sample: sampleBuffer, to: self.micAudioWriterInput)
|
|
131
|
+
default:
|
|
132
|
+
break
|
|
133
|
+
}
|
|
134
|
+
if (!sent) {
|
|
135
|
+
handler(nil)
|
|
136
|
+
sent = true
|
|
137
|
+
}
|
|
138
|
+
})
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
private func handleSampleBuffer(sampleBuffer: CMSampleBuffer) {
|
|
142
|
+
if self.videoWriter?.status == AVAssetWriter.Status.unknown {
|
|
143
|
+
self.videoWriter?.startWriting()
|
|
144
|
+
self.videoWriter?.startSession(atSourceTime: CMSampleBufferGetPresentationTimeStamp(sampleBuffer))
|
|
145
|
+
} else if self.videoWriter?.status == AVAssetWriter.Status.writing &&
|
|
146
|
+
self.videoWriterInput?.isReadyForMoreMediaData == true {
|
|
147
|
+
self.videoWriterInput?.append(sampleBuffer)
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
private func add(sample: CMSampleBuffer, to writerInput: AVAssetWriterInput?) {
|
|
152
|
+
if writerInput?.isReadyForMoreMediaData ?? false {
|
|
153
|
+
writerInput?.append(sample)
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/**
|
|
158
|
+
Stops recording the content of the application screen, after calling startRecording
|
|
159
|
+
|
|
160
|
+
- Parameter errorHandler: Called when an error is found
|
|
161
|
+
*/
|
|
162
|
+
public func stoprecording(handler: @escaping (Error?) -> Void) {
|
|
163
|
+
recorder.stopCapture( handler: { error in
|
|
164
|
+
if let error = error {
|
|
165
|
+
handler(error)
|
|
166
|
+
} else {
|
|
167
|
+
self.videoWriterInput?.markAsFinished()
|
|
168
|
+
self.micAudioWriterInput?.markAsFinished()
|
|
169
|
+
self.appAudioWriterInput?.markAsFinished()
|
|
170
|
+
self.videoWriter?.finishWriting {
|
|
171
|
+
self.saveVideoToCameraRollAfterAuthorized(handler: handler)
|
|
172
|
+
}
|
|
173
|
+
}
|
|
174
|
+
})
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
private func saveVideoToCameraRollAfterAuthorized(handler: @escaping (Error?) -> Void) {
|
|
178
|
+
if PHPhotoLibrary.authorizationStatus() == .authorized {
|
|
179
|
+
self.saveVideoToCameraRoll(handler: handler)
|
|
180
|
+
} else {
|
|
181
|
+
PHPhotoLibrary.requestAuthorization({ (status) in
|
|
182
|
+
if status == .authorized {
|
|
183
|
+
self.saveVideoToCameraRoll(handler: handler)
|
|
184
|
+
} else {
|
|
185
|
+
handler(ScreenRecorderError.photoLibraryAccessNotGranted)
|
|
186
|
+
}
|
|
187
|
+
})
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
private func saveVideoToCameraRoll(handler: @escaping (Error?) -> Void) {
|
|
192
|
+
guard let videoOutputURL = self.videoOutputURL else {
|
|
193
|
+
return handler(nil)
|
|
194
|
+
}
|
|
195
|
+
|
|
196
|
+
PHPhotoLibrary.shared().performChanges({
|
|
197
|
+
PHAssetChangeRequest.creationRequestForAssetFromVideo(atFileURL: videoOutputURL)
|
|
198
|
+
}, completionHandler: { _, error in
|
|
199
|
+
if let error = error {
|
|
200
|
+
handler(error)
|
|
201
|
+
} else {
|
|
202
|
+
handler(nil)
|
|
203
|
+
}
|
|
204
|
+
})
|
|
205
|
+
}
|
|
206
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@capgo/capacitor-screen-recorder",
|
|
3
|
+
"version": "1.2.0",
|
|
4
|
+
"description": "Record device's screen",
|
|
5
|
+
"main": "dist/plugin.cjs.js",
|
|
6
|
+
"module": "dist/esm/index.js",
|
|
7
|
+
"types": "dist/esm/index.d.ts",
|
|
8
|
+
"unpkg": "dist/plugin.js",
|
|
9
|
+
"files": [
|
|
10
|
+
"android/src/main/",
|
|
11
|
+
"android/build.gradle",
|
|
12
|
+
"dist/",
|
|
13
|
+
"ios/Plugin/",
|
|
14
|
+
"CapacitorScreenRecorder.podspec"
|
|
15
|
+
],
|
|
16
|
+
"author": "Martin Donadieu",
|
|
17
|
+
"license": "MIT",
|
|
18
|
+
"repository": {
|
|
19
|
+
"type": "git",
|
|
20
|
+
"url": "git+https://github.com/riderx/capacitor-screen-recorder.git"
|
|
21
|
+
},
|
|
22
|
+
"bugs": {
|
|
23
|
+
"url": "https://github.com/riderx/capacitor-screen-recorder/issues"
|
|
24
|
+
},
|
|
25
|
+
"keywords": [
|
|
26
|
+
"capacitor",
|
|
27
|
+
"plugin",
|
|
28
|
+
"native"
|
|
29
|
+
],
|
|
30
|
+
"scripts": {
|
|
31
|
+
"verify": "npm run verify:ios && npm run verify:android && npm run verify:web",
|
|
32
|
+
"verify:ios": "cd ios && pod install && xcodebuild -workspace Plugin.xcworkspace -scheme Plugin && cd ..",
|
|
33
|
+
"verify:android": "cd android && ./gradlew clean build test && cd ..",
|
|
34
|
+
"verify:web": "npm run build",
|
|
35
|
+
"lint": "npm run eslint && npm run prettier -- --check && npm run swiftlint -- lint",
|
|
36
|
+
"fmt": "npm run eslint -- --fix && npm run prettier -- --write && npm run swiftlint -- --fix --format",
|
|
37
|
+
"eslint": "eslint . --ext ts",
|
|
38
|
+
"prettier": "prettier \"**/*.{css,html,ts,js,java}\"",
|
|
39
|
+
"swiftlint": "node-swiftlint",
|
|
40
|
+
"docgen": "docgen --api ScreenRecorderPlugin --output-readme README.md --output-json dist/docs.json",
|
|
41
|
+
"build": "npm run clean && npm run docgen && tsc && rollup -c rollup.config.js",
|
|
42
|
+
"clean": "rimraf ./dist",
|
|
43
|
+
"watch": "tsc --watch",
|
|
44
|
+
"prepublishOnly": "npm run build"
|
|
45
|
+
},
|
|
46
|
+
"devDependencies": {
|
|
47
|
+
"@capacitor/android": "^3.0.0",
|
|
48
|
+
"@capacitor/core": "^3.0.0",
|
|
49
|
+
"@capacitor/docgen": "^0.0.10",
|
|
50
|
+
"@capacitor/ios": "^3.0.0",
|
|
51
|
+
"@ionic/eslint-config": "^0.3.0",
|
|
52
|
+
"@ionic/prettier-config": "^1.0.1",
|
|
53
|
+
"@ionic/swiftlint-config": "^1.1.2",
|
|
54
|
+
"eslint": "^7.11.0",
|
|
55
|
+
"prettier": "~2.2.0",
|
|
56
|
+
"prettier-plugin-java": "~1.0.0",
|
|
57
|
+
"rimraf": "^3.0.2",
|
|
58
|
+
"rollup": "^2.32.0",
|
|
59
|
+
"swiftlint": "^1.0.1",
|
|
60
|
+
"typescript": "~4.0.3"
|
|
61
|
+
},
|
|
62
|
+
"peerDependencies": {
|
|
63
|
+
"@capacitor/core": "^3.0.0"
|
|
64
|
+
},
|
|
65
|
+
"prettier": "@ionic/prettier-config",
|
|
66
|
+
"swiftlint": "@ionic/swiftlint-config",
|
|
67
|
+
"eslintConfig": {
|
|
68
|
+
"extends": "@ionic/eslint-config/recommended"
|
|
69
|
+
},
|
|
70
|
+
"capacitor": {
|
|
71
|
+
"ios": {
|
|
72
|
+
"src": "ios"
|
|
73
|
+
},
|
|
74
|
+
"android": {
|
|
75
|
+
"src": "android"
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
}
|