ksnowlv

回顾过去,总结以往;立足现在,铭记当下;技术为主,笔记而已.

Mac安装Maven

| Comments

一.下载apache-maven-3.6.3见:Maven官网

apache-maven-3.6.3放置到/Users/用户名/目录下

二.配置环境变量

打开.bash_profile文件,配置如下:

export MAVENDIR=/Users/ksnowlv/apache-maven-3.6.3
export PATH=$PATH:$MAVENDIR/bin:$PATH

使用source ~/.bash_profile命令使环境变量生效

三.测试是否安装成功

使用mvn -v命名测试

1.若成功输出如下内容
ksnowlvdeMacBook-Pro:QUICTest ksnowlv$ mvn -version
Picked up JAVA_TOOL_OPTIONS: -Dfile.encoding=UTF-8
Apache Maven 3.6.3 (cecedd343002696d0abb50b32b541b8a6ba2883f)
Maven home: /Users/ksnowlv/apache-maven-3.6.3
Java version: 12, vendor: Oracle Corporation, runtime: /Library/Java/   JavaVirtualMachines/jdk-12.jdk/Contents/Home
Default locale: zh_CN_#Hans, platform encoding: UTF-8
OS name: "mac os x", version: "10.15", arch: "x86_64", family: "mac"
2.若失败,如下内容,更新下JAVA_HOME目录即可。
The JAVA_HOME environment variable is not defined correctly
This environment variable is needed to run this program
NB: JAVA_HOME should point to a JDK not a JRE

iOS视频播放AVPlayerViewController

| Comments

AVPlayerViewController播放视频分两种形式

  • 内嵌视图的形式显示
  • 模态视图的形式显示

一.初始化AVPlayerViewController

1
2
3
4
5
6
7
8
9
10
 func loadPlayer() -> Void {
        guard let movieUrl = Bundle.main.path(forResource: "zh-zhfanti-en", ofType: "m4v") else {
            return
        }

        let player = AVPlayer(url: URL(fileURLWithPath: movieUrl))
        playerViewController = AVPlayerViewController()
        playerViewController!.player = player
    }

二.内嵌视图的形式显示

1
2
3
4
5
6
7
8
9
10
11
12
13
 @IBAction func handlePlayInViewEvent(sender: AnyObject) {
        loadPlayer()

        guard (playerViewController != nil) else {
            return
        }

        containerView?.addSubview(playerViewController!.view)
        playerViewController?.view.frame = containerView!.bounds
        self.addChild(playerViewController!)
        playerViewController?.player?.play()
   }

效果图如下:

点击AVPlayerViewController可以全屏播放

三.模态视图的形式显示

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
@IBAction func handlePlayWithModelViewEvent(sender: AnyObject) {

    loadPlayer()

    guard (playerViewController != nil) else {
        return
    }


    self.present(playerViewController!, animated: true) { [weak self] () -> Void in
        guard let self = self else {
            return
        }
        self.playerViewController?.player?.play()
    }
}

效果图如下:

四.停止视频播放

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
 @IBAction func handleStopPlayEvent(sender: AnyObject? ){

        guard playerViewController != nil else {
            return
        }

        if ((playerViewController?.parent) != nil) {
            playerViewController?.view.removeFromSuperview()
            playerViewController?.removeFromParent()
        } else if playerViewController != nil && playerViewController!.isModalInPresentation {
            playerViewController?.dismiss(animated: (sender != nil ? true:false), completion: nil)
        }

        playerViewController?.player?.pause()
        playerViewController = nil
  }

iOS视频播放-AVPlayer和AVPlayerLayer

| Comments

本文计划使用AVPlayerAVPlayerLayer播放视频格式

  • m4v:MP4的特殊类型,MP4格式的高清;可包含字幕
  • mp4:音频、视频信息的压缩编码标准。
  • srt:字幕文件格式

一.播放m4v格式

可通过MP4格式的文件+字幕文件合成m4v格式,可用Subler工具合成

image

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
 func playMovieFromLocalFile(fileFullName: String) -> Bool {

        guard FileManager.default.fileExists(atPath: fileFullName) else {
            debugPrint("\(fileFullName) not Found")
            return false
        }

        //加载视频文件资源(包括视频与所有字幕)
        let asset = AVAsset(url: URL(fileURLWithPath: fileFullName))
        let playerItem = AVPlayerItem(asset: asset)

        //视频文件中所有支持的字幕
        for characteristic in asset.availableMediaCharacteristicsWithMediaSelectionOptions {

            debugPrint("\(characteristic)")

            if let group = asset.mediaSelectionGroup(forMediaCharacteristic: characteristic) {
                for option in group.options {
                    debugPrint("  Option: \(option.displayName)")
                }
            }
        }

        if let group = asset.mediaSelectionGroup(forMediaCharacteristic: AVMediaCharacteristic.legible) {

            let locale = Locale(identifier: "zh")
            let options =
                AVMediaSelectionGroup.mediaSelectionOptions(from: group.options, with: locale)
            if let option = options.first {
                // 如果支持中文,默认选中中文字幕
                playerItem.select(option, in: group)
            }
        }

        player = AVPlayer(playerItem: playerItem)
        player?.appliesMediaSelectionCriteriaAutomatically = false

        if playerLayer == nil {
            playerLayer = AVPlayerLayer(player: player)
            playerLayer?.videoGravity = AVLayerVideoGravity.resizeAspectFill
            playerContainerView?.layer.addSublayer(playerLayer!)
        }

        setupPlayerObserverEvent()

        return true
    }


    override func viewDidAppear(_ animated: Bool) {
        playerLayer?.frame = playerContainerView!.bounds
    }

效果图如下:

image

二.播放mp4格式带srt字幕

mp4文件和字幕srt文件通过时间軕实现当前播放进度展示相应文本。 srt格式解析可参考AVPlayerViewController-Subtitles

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22

  func playMovie(movieFile: String, captionFile: String) -> Bool {

        let fileManage = FileManager.default
        guard fileManage.fileExists(atPath: movieFile) && fileManage.fileExists(atPath: captionFile) else {
            debugPrint("movie:\(movieFile)/ or captionFile:\(captionFile)not found")
            return false
        }

        //加载视频文件
        player =  AVPlayer(url: URL(fileURLWithPath: movieFile))
        //加载视频文件对应字幕文件
        parser = Subtitles(file: URL(fileURLWithPath: captionFile))

        //创建AVPlayerLayer并加入到视图层中
        playerLayer = AVPlayerLayer(player: player)
        playerLayer!.videoGravity = AVLayerVideoGravity.resizeAspectFill
        playerContainerView?.layer.addSublayer(playerLayer!)
        setupPlayerObserverEvent()

        return true
    }

效果图如下:

image

三.两种方式需要手动播放或暂停

1
2
3
4
5
6
7
8
9
10
11
12
13

    @IBAction func handleStartPlayerEvent(sender: AnyObject) {
        isPlaying = true
        player?.play()
    }

    @IBAction func handlePausePlayerEvent(sender: AnyObject) {

        if isPlaying {
            player?.pause()
        }
    }

详细参考源代码

XCode使用PMD扫描重复代码(一)

| Comments

如何使用PMD在Xcode下扫描重复代码(Copy&Past)呢?

1.下载PMD:https://pmd.github.io,放置到工程主目录下面。

image

2.Xcode中检测脚本配置

1.在XcodeBuild Phases 中,我们增加一个新的 Run Script,脚本内容如下:

#检测swift代码
#pmd cpd --files ${EXECUTABLE_NAME} --minimum-tokens 50 --language swift --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer > cpd-output.xml --failOnViolation true

#检测objective-c代码
pmd cpd --files ${EXECUTABLE_NAME} --minimum-tokens 20 --language objectivec --encoding UTF-8 --format net.sourceforge.pmd.cpd.XMLRenderer > cpd-output.xml --failOnViolation true

# Running script
php ./cpd_script.php -cpd-xml cpd-output.xml

2.在工程主目录下,创建cpd_script.php文件

!!!需要安装好php

<?php
foreach (simplexml_load_file('cpd-output.xml')->duplication as $duplication) {
    $files = $duplication->xpath('file');
    foreach ($files as $file) {
        echo $file['path'].':'.$file['line'].':1: warning: '.$duplication['lines'].' copy-pasted lines from: '
            .implode(', ', array_map(function ($otherFile) { return $otherFile['path'].':'.$otherFile['line']; },
            array_filter($files, function ($f) use (&$file) { return $f != $file; }))).PHP_EOL;
    }
}
?>

image

flutter创建工程报错:Cannot Create a Project Within the Flutter SDK. Target Directory ‘X’ Is Within the Flutter SDK at’/Users/x/Music/flutter/flutter’

| Comments

在使用 flutter create命令创建flutter工程时,如果报Cannot create a project within the Flutter SDK. Target directory '/Users/ksnowlv/Music/flutter/flutter/my_app' is within the Flutter SDK at '/Users/ksnowlv/Music/flutter/flutter'的错误,注意不要在flutter SDK目录及子目录下创建工程,可考虑在其它目录下创建工程。例如平级目录

ksnowlvdeMacBook-Pro:flutter ksnowlv$ ./flutter/bin/flutter create my_app
Creating project my_app...
  my_app/ios/Runner.xcworkspace/contents.xcworkspacedata (created)
  my_app/ios/Runner/Info.plist (created)
  my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage@3x.png (created)
  my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/README.md (created)
  my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/Contents.json (created)
  my_app/ios/Runner/Assets.xcassets/LaunchImage.imageset/LaunchImage.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@1x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@1x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@1x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-1024x1024@1x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-83.5x83.5@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@3x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Contents.json (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-20x20@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@3x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@3x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-60x60@2x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-76x76@1x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-40x40@3x.png (created)
  my_app/ios/Runner/Assets.xcassets/AppIcon.appiconset/Icon-App-29x29@2x.png (created)
  my_app/ios/Runner/Base.lproj/LaunchScreen.storyboard (created)
  my_app/ios/Runner/Base.lproj/Main.storyboard (created)
  my_app/ios/Runner.xcodeproj/project.xcworkspace/contents.xcworkspacedata (created)
  my_app/ios/Runner.xcodeproj/xcshareddata/xcschemes/Runner.xcscheme (created)
  my_app/ios/Flutter/Debug.xcconfig (created)
  my_app/ios/Flutter/Release.xcconfig (created)
  my_app/ios/Flutter/AppFrameworkInfo.plist (created)
  my_app/test/widget_test.dart (created)
  my_app/my_app.iml (created)
  my_app/.gitignore (created)
  my_app/.metadata (created)
  my_app/ios/Runner/AppDelegate.h (created)
  my_app/ios/Runner/main.m (created)
  my_app/ios/Runner/AppDelegate.m (created)
  my_app/ios/Runner.xcodeproj/project.pbxproj (created)
  my_app/android/app/src/profile/AndroidManifest.xml (created)
  my_app/android/app/src/main/res/mipmap-mdpi/ic_launcher.png (created)
  my_app/android/app/src/main/res/mipmap-hdpi/ic_launcher.png (created)
  my_app/android/app/src/main/res/drawable/launch_background.xml (created)
  my_app/android/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png (created)
  my_app/android/app/src/main/res/mipmap-xxhdpi/ic_launcher.png (created)
  my_app/android/app/src/main/res/values/styles.xml (created)
  my_app/android/app/src/main/res/mipmap-xhdpi/ic_launcher.png (created)
  my_app/android/app/src/main/AndroidManifest.xml (created)
  my_app/android/app/src/debug/AndroidManifest.xml (created)
  my_app/android/gradle/wrapper/gradle-wrapper.properties (created)
  my_app/android/gradle.properties (created)
  my_app/android/settings.gradle (created)
  my_app/pubspec.yaml (created)
  my_app/README.md (created)
  my_app/lib/main.dart (created)
  my_app/android/app/build.gradle (created)
  my_app/android/app/src/main/java/com/example/my_app/MainActivity.java (created)
  my_app/android/build.gradle (created)
  my_app/android/my_app_android.iml (created)
  my_app/.idea/runConfigurations/main_dart.xml (created)
  my_app/.idea/libraries/Flutter_for_Android.xml (created)
  my_app/.idea/libraries/Dart_SDK.xml (created)
  my_app/.idea/libraries/KotlinJavaRuntime.xml (created)
  my_app/.idea/modules.xml (created)
  my_app/.idea/workspace.xml (created)
Running "flutter packages get" in my_app...                         5.7s
Wrote 66 files.

All done!
[✓] Flutter is fully installed. (Channel dev, v1.6.0, on Mac OS X 10.14.4 18E226, locale zh-Hans-CN)
[!] Android toolchain - develop for Android devices is partially installed; more components are available. (Android SDK version 28.0.3)
[!] iOS toolchain - develop for iOS devices is partially installed; more components are available. (Xcode 10.2.1)
[!] Android Studio is partially installed; more components are available. (version 3.4)
[!] Connected device is not available.

Run "flutter doctor" for information about installing additional components.

In order to run your application, type:

  $ cd my_app
  $ flutter run

Your application code is in my_app/lib/main.dart.

ksnowlvdeMacBook-Pro:flutter ksnowlv$ 

Flutter安装和运行

| Comments

1.创建flutter工程目录(各项目+flutter目录),在flutter 目录下载flutter SDK

git init
git clone -b dev https://github.com/flutter/flutter.git

2.进入flutter SDK目录即flutter禁用通过 Google Analytics 发送数据

cd flutter
./bin/flutter config --no-analytics

禁用通过 Google Analytics 发送相关数据,以免国内网络连接失败问题。

3.检查flutter安装情况:flutter doctor

ksnowlvdeMacBook-Pro:flutter ksnowlv$ ./bin/flutter doctor
Downloading Material fonts...                                       0.7s
Downloading android-arm-profile/darwin-x64 tools...                 1.3s
Downloading android-arm-release/darwin-x64 tools...                 1.2s
Downloading android-arm64-profile/darwin-x64 tools...               1.4s
Downloading android-arm64-release/darwin-x64 tools...               1.4s
Downloading android-x86 tools...                                    6.6s
Downloading android-x64 tools...                                    6.8s
Downloading android-arm tools...                                    3.1s
Downloading android-arm-profile tools...                            2.0s
Downloading android-arm-release tools...                            1.5s
Downloading android-arm64 tools...                                  3.2s
Downloading android-arm64-profile tools...                          2.1s
Downloading android-arm64-release tools...                          1.5s
Downloading ios tools...                                           16.0s
Downloading ios-profile tools...                                   11.7s
Downloading ios-release tools...                                    8.9s
Downloading Gradle Wrapper...                                       0.3s
Downloading package sky_engine...                                   1.1s
Downloading common tools...                                         4.2s
Downloading common tools...                                         4.1s
Downloading darwin-x64 tools...                                    14.0s
Doctor summary (to see all details, run flutter doctor -v):
[✓] Flutter (Channel dev, v1.6.0, on Mac OS X 10.14.4 18E226, locale zh-Hans-CN)
[!] Android toolchain - develop for Android devices (Android SDK version 28.0.3)
    ✗ Android license status unknown.
      Try re-installing or updating your Android SDK Manager.
      See https://developer.android.com/studio/#downloads or visit https://flutter.dev/setup/#android-setup for detailed instructions.
[!] iOS toolchain - develop for iOS devices
    ✗ Xcode installation is incomplete; a full installation is necessary for iOS development.
      Download at: https://developer.apple.com/xcode/download/
      Or install Xcode via the App Store.
      Once installed, run:
        sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
    ✗ libimobiledevice and ideviceinstaller are not installed. To install with Brew, run:
        brew update
        brew install --HEAD usbmuxd
        brew link usbmuxd
        brew install --HEAD libimobiledevice
        brew install ideviceinstaller
    ✗ ios-deploy not installed. To install:
        brew install ios-deploy
[!] Android Studio (version 3.4)
    ✗ Flutter plugin not installed; this adds Flutter specific functionality.
    ✗ Dart plugin not installed; this adds Dart specific functionality.
[!] Connected device
    ! No devices available

! Doctor found issues in 4 categories.

4.安装XCode和打开iOS模拟器

  • 安装XCode

    • 我机器安装的XCode版本是10.2.1,比较新了。如果安装的版本较老,可以更新下

        ksnowlvdeMacBook-Pro:flutter ksnowlv$ sudo xcode-select --switch /Applications/Xcode.app/Contents/Developer
                Password:
      
  • 打开模拟器

    • 在Mac机器上,可以通过 open -a Simulator

5.创建工程

使用flutter create 项目名称创建项目

在使用 flutter create命令创建flutter工程时,如果报Cannot create a project within the Flutter SDK. Target directory '/Users/ksnowlv/Music/flutter/flutter/my_app' is within the Flutter SDK at '/Users/ksnowlv/Music/flutter/flutter'的错误,注意不要在flutter SDK目录及子目录下创建工程,可考虑在其它目录下创建工程。例如平级目录

6.运行工程

使用flutter run运行app,

../flutter/bin/flutter run

image

image

Swift泛型

| Comments

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
/// 交换两个对象的值
///
/// - Parameters:
///   - aValue: 对象a
///   - bValue: 对象b
func swapValues<T>(_ aValue: inout T, _ bValue: inout T) {
    let temp = aValue
    aValue = bValue
    bValue = temp
}

/// 栈模板
struct QStack<T> {

    var items = [T]()
    mutating func push(_ item: T) {
        items.append(item)
    }

    mutating func pop() -> T {
        return self.items.removeLast()
    }

    func isEmpty() -> Bool {
       return (0 == self.items.count)
    }

    var count: Int {
        return self.items.count
    }

    subscript(i: Int) -> T {
        return self.items[i]
    }
}

Python筛选目录下非jpeg,png,bmp格式的图片

| Comments

功能:筛选指定目录下非jpeg/png/bmp格式的文件,并把路径以日志形式输出。

关键有两点:

  • 目录遍历,记录所有文件路径。
  • 遍历路径,使用imghdr.what判断文件格式,非jpeg/png/bmp格式的文件路径输出。

python3.0实现如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
import os
import imghdr

##工具功能:筛选目录下非jpeg,png,bmp格式的图片,并输出其路径
##Python 3.0

#图片文件夹目录
IMAGEPATH = None

#初始化
def init():
    global IMAGEPATH
    IMAGEPATH  = "/Users/ksnowlv/Documents/image"


# 功能:读取指定目录下的所有文件绝对路径(包括该目录下所有子目录),并以列表形式返回

def readDir(dirPath):
    myDirPath = dirPath
    if dirPath.endswith('/'):# 要求传入的路径参数最后不能有斜杠,目的是为了递归时格式统一
        myDirPath = dirPath.rstrip('/')
        print('文件夹路径末尾删除/ = %s'%(myDirPath))

    allFiles = []

    if os.path.isdir(myDirPath):
        fileList = os.listdir(myDirPath)
        for f in fileList:
            f = myDirPath+'/'+f
            if os.path.isdir(f):
                subFiles = readDir(f)
                allFiles = subFiles + allFiles #合并当前目录与子目录的所有文件路径
            else:
                allFiles.append(f)
        return allFiles
    else:
        print('Error,not a dir')
    return allFiles

#根据路径筛选出非目标图片的路径
def filterPicture(fileList):
    for fileName in fileList:
        # data = open(fileName, 'rb').read(20)
        fileType = imghdr.what(fileName)
        # print("filename = %s fileType = %s" % (fileName,fileType))

        if fileType != "jpeg" and fileType != "png" and fileType != "bmp":
            print("filename = %s can not parse fileType = %s " % (fileName, fileType))

def main():
    init()
    fileList = readDir(IMAGEPATH)
    filterPicture(fileList)


if __name__ == '__main__':
    main()

Kotlin通过jni间接调用c++

| Comments

本篇重点内容,Kotlin通过JNI直接调用C,C调用C++相关的类。实际上只是JAVA换成Kotlin的写法而已。

一.添加Kotlin类KotlinPerson

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
class KotlinPerson {

    var mPerson: Long = 0

    init {
        mPerson = createPerson()
    }

    fun setPersonName(name: String) {
        setName(mPerson, name)
    }

    fun personName(): String {
        return name(mPerson)
    }


    fun setPersonAge(age: Int) {
        setAge(mPerson,age)
    }

    fun personAge() : Int {
        return age(mPerson)
    }

    companion object {
        init {
            System.loadLibrary("JNIPerson")
        }
    }

    external fun createPerson(): Long
    external fun destroyPerson(person: Long)
    external fun setName(person: Long, name: String)
    external fun name(person: Long): String
    external fun setAge(person: Long, age: Int)
    external fun age(person: Long): Int
}

二.添加JNI接口及实现

JNIPerson.c内容如下:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
  #include "JNIPerson.h"
  #include "PersonExtension.hpp"
  #include "JNILog.h"
  #include <stdlib.h>
  #include <string.h>
  
  
    /*
    * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
    * Method:    createPerson
    * Signature: ()Ljava/lang/Object;
    */
  JNIEXPORT jlong JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_createPerson
      (JNIEnv *env, jobject cls) {
  
  
        void *p = createPerson();
  
        return (jlong)p;
      }
  
    /*
    * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
    * Method:    destroyPerson
    * Signature: (Ljava/lang/Object;)V
    */
    JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_destroyPerson
      (JNIEnv *env, jobject cls, jlong o) {
  
          destroyPerson((void*)o);
      }
  
    /*
    * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
    * Method:    setPersonAge
    * Signature: (Ljava/lang/Object;I)V
    */
    JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_setAge
      (JNIEnv *env, jobject cls, jlong o, jint value) {
        setPersonAge((void*)o,value);
      }
  
    /*
    * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
    * Method:    personAge
    * Signature: (Ljava/lang/Object;)I
    */
    JNIEXPORT jint JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_age
      (JNIEnv *env, jobject cls, jlong o) {
       return personAge((void*)o);
      }
  
  
    JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_setName
      (JNIEnv *env, jobject cls, jlong o, jstring string) {
  
        int length1 = (*env)->GetStringLength(env, string);
        const jchar * jcstr = (*env)->GetStringChars(env, string, NULL);
  
  
         jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");  //String
         jstring   code   =   (*env)->NewStringUTF(env,"UTF-8"); //"UTF-8"
         jmethodID   methodID   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B"); //getBytes();
         jbyteArray   byteArray =   (jbyteArray)(*env)->CallObjectMethod(env,string,methodID,code);
         jsize   length   =   (*env)->GetArrayLength(env,byteArray);
         jbyte*   bytes   =   (*env)->GetByteArrayElements(env,byteArray,JNI_FALSE);
  
  
         if( length > 0){
  
            char* buf =   (char*)malloc(length+1);         //"\0"
            memcpy(buf,bytes,length);
            buf[length]=0;
            setPersonName((void*)o, buf);
            LOGI("set name = %s",buf);
            free(buf);
         }else{
            setPersonName((void*)o, NULL);
         }
  
         (*env)->ReleaseByteArrayElements(env,byteArray,bytes,0);  //释放内存空间
      }
  
    /*
    * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
    * Method:    personName
    * Signature: (Ljava/lang/Object;)Ljava/lang/String;
    */
    JNIEXPORT jstring JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_name
      (JNIEnv *env, jobject cls, jlong o) {
  
        LOGI("jni get name");
        const char *name = personName((void*)o);
  
        if ( name != NULL ) {
            LOGI("jni name = %s",name);
            return  (*env)->NewStringUTF(env,name);
        }else {
            return (*env)->NewStringUTF(env,"");
        }
      }
  #include "JNIPerson.h"
#include "PersonExtension.hpp"
#include "JNILog.h"
#include <stdlib.h>
#include <string.h>


  /*
   * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
   * Method:    createPerson
   * Signature: ()Ljava/lang/Object;
   */
JNIEXPORT jlong JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_createPerson
    (JNIEnv *env, jobject cls) {


      void *p = createPerson();

      return (jlong)p;
    }

  /*
   * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
   * Method:    destroyPerson
   * Signature: (Ljava/lang/Object;)V
   */
  JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_destroyPerson
    (JNIEnv *env, jobject cls, jlong o) {

        destroyPerson((void*)o);
    }

  /*
   * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
   * Method:    setPersonAge
   * Signature: (Ljava/lang/Object;I)V
   */
  JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_setAge
    (JNIEnv *env, jobject cls, jlong o, jint value) {
      setPersonAge((void*)o,value);
    }

  /*
   * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
   * Method:    personAge
   * Signature: (Ljava/lang/Object;)I
   */
  JNIEXPORT jint JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_age
    (JNIEnv *env, jobject cls, jlong o) {
     return personAge((void*)o);
    }


  JNIEXPORT void JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_setName
    (JNIEnv *env, jobject cls, jlong o, jstring string) {

      int length1 = (*env)->GetStringLength(env, string);
      const jchar * jcstr = (*env)->GetStringChars(env, string, NULL);


       jclass   clsstring   =   (*env)->FindClass(env,"java/lang/String");  //String
       jstring   code   =   (*env)->NewStringUTF(env,"UTF-8"); //"UTF-8"
       jmethodID   methodID   =   (*env)->GetMethodID(env,clsstring,   "getBytes",   "(Ljava/lang/String;)[B"); //getBytes();
       jbyteArray   byteArray =   (jbyteArray)(*env)->CallObjectMethod(env,string,methodID,code);
       jsize   length   =   (*env)->GetArrayLength(env,byteArray);
       jbyte*   bytes   =   (*env)->GetByteArrayElements(env,byteArray,JNI_FALSE);


       if( length > 0){

          char* buf =   (char*)malloc(length+1);         //"\0"
          memcpy(buf,bytes,length);
          buf[length]=0;
          setPersonName((void*)o, buf);
          LOGI("set name = %s",buf);
          free(buf);
       }else{
          setPersonName((void*)o, NULL);
       }

       (*env)->ReleaseByteArrayElements(env,byteArray,bytes,0);  //释放内存空间
    }

  /*
   * Class:     com_ksnowlv_hellojniforjava_JavaCallJNI
   * Method:    personName
   * Signature: (Ljava/lang/Object;)Ljava/lang/String;
   */
  JNIEXPORT jstring JNICALL Java_com_ksnowlv_kotlinjni_KotlinPerson_name
    (JNIEnv *env, jobject cls, jlong o) {

      LOGI("jni get name");
      const char *name = personName((void*)o);

      if ( name != NULL ) {
          LOGI("jni name = %s",name);
          return  (*env)->NewStringUTF(env,name);
      }else {
          return (*env)->NewStringUTF(env,"");
      }
    }

三.调用

1
2
3
4
5
6
7
var person = KotlinPerson()
person.setPersonAge(10)

Log.i("----Android age = ", "" + person.personAge())
person.setPersonName("ksnowlv(律威)")

Log.i("----Android name = ", person.personName())

四.日志输出

Included file 'custom/after_footer.html' not found in _includes directory