Skip to main content

Installation

Add Avatars Swift package from git.
https://github.com/avatechgg/avatars-swift.git

How it works

In order to make the Avatar SDK works in ios environment, we have built a simple frontend and wrap it up with WKWebView. All data input from ios app will be sent to the webview and takes effect after handling. Therefore, please turn on Outgoing Connections (Client), otherwise webview will not work.
Webview config

The Code

You need to first import the package and create a stateObject with AvatarViewModel(). It contain various data for creating the AvatarView.
import Avatars

struct ContentView: View {
    // Data the frontend needed to create the canvas.
    @StateObject var viewModel = AvatarViewModel(
        // The id of avatar you created
        avatarId: "fb4051f8-5969-480f-b57b-fcfc66c5b6f6",

        // Model position
        x: 0,
        y: 0,

        // Model scale & rotation
        scale: 1,
        rotation: 0,

        // For emotion setting
        currentEmotion: ""
    )
}
Then you can create the AvatarView in body with the stateObject to create the canvas.
var body: some View {
    VStack {
        AvatarView(viewModel) // The canvas showing Avatar
    }
}
import SwiftUI
import Avatars

struct ContentView: View {
@StateObject var viewModel = AvatarViewModel(
        // The id of avatar you created
        avatarId: "fb4051f8-5969-480f-b57b-fcfc66c5b6f6",

        // Model position
        x: 0,
        y: 0,

        // Model scale & rotation
        scale: 1,
        rotation: 0,

        // For emotion setting
        currentEmotion: ""
    )

    @State private var textInput = ""

    var body: some View {
        VStack {
            AvatarView(viewModel) // The canvas showing Avatar

            HStack {
                TextField("Enter audio source", text: $textInput)
                    .textFieldStyle(RoundedBorderTextFieldStyle())
                Button("Send") {
                    viewModel.audioSource = textInput
                }
                .padding(.leading, 8)
            }
            .padding(.horizontal)

            Button("Show Controls") {
                isSheetPresented = true
            }
            .padding()
        }
        .padding()
        .sheet(isPresented: $isSheetPresented) {
            PositionControlSheet(viewModel)
        }
    }

}

struct ContentView_Previews: PreviewProvider {
    static var previews: some View {
        ContentView()
    }
}

Advance settings

Avatars Swift package also support avatar interaction incluing audio lip-sync and emotions.
  • Emotions the avatar support is stored at viewModel.availableEmotion
  • You can change the emotion of avatar by changing viewModel.currentEmotion
  • After changing the emotion, it will reset to neutral after serveal second.

Example

struct EmotionGroup: View {
    @ObservedObject var viewModel: AvatarViewModel
    @State private var selectedEmotion = ""

    init(_ viewModel: AvatarViewModel) {
        self.viewModel = viewModel
    }

    var body: some View {
        HStack {
            if (viewModel.availableEmotion != nil) {
                Text("Emotion: ")
                Picker(selection: $selectedEmotion, label: Text("Emotion")) {
                    Text("---").tag("")
                    ForEach(viewModel.availableEmotion!, id: \.self){
                        Text($0)
                    }
                }.pickerStyle(MenuPickerStyle()).onChange(of: selectedEmotion) {
                    selectedEmotion in
                    if(selectedEmotion == "") {
                        return
                    }
                    viewModel.currentEmotion = selectedEmotion
                }

            }
        }
    }
}
You can import audio by changing the value of audioSource or rawBase64Audio from the stateObject.If your audio source is an url, you should pass the string to the webview with audioSource.If your audio source is in data format, you should encode it with base64 format using base64EncodedString() and pass the data to the webview with rawBase64Audio.The audio will be played and lip-sync will start automatically once the value is changed.If you send another audio to webview while previous audio is playing, webview will automatically store the new audio and play it after previous audio end.

Example

struct AudioGroup: View {

    @ObservedObject var viewModel: AvatarViewModel
    @State private var textInput = ""
    @State private var isImporting: Bool = false
    
    init(_ viewModel: AvatarViewModel) {
        self.viewModel = viewModel
    }
    
    var body: some View {
        HStack {
            // import audio url

            TextField("Enter audio source", text: $textInput)
                .textFieldStyle(RoundedBorderTextFieldStyle())
            Button("Send") {
                viewModel.audioSource = textInput
            }
            .padding(.leading, 8)
            
            // import audio data
            Button(action: {
                isImporting.toggle()
            }, label: {
                Text("Import")
            })
        }.fileImporter(
            isPresented: $isImporting,
            allowedContentTypes: [UTType.audio],
            allowsMultipleSelection: false
        ) { result in
            do {
                guard let selectedFile: URL = try result.get().first else { return }
                guard selectedFile.startAccessingSecurityScopedResource() else { return }
                
                let audioData =  try Data(contentsOf: selectedFile)
                let encodedString = audioData.base64EncodedString()
                
                viewModel.rawBase64Audio = encodedString
                
                selectedFile.stopAccessingSecurityScopedResource()
            } catch {
                Swift.print(error.localizedDescription)
            }
        }
    }
}

References

AvatarViewModel

FieldTypeDescription
avatarIdStringThe id of the avatar you created. You can create you own avatar at here!
xFloatThe position of the avatar on the x axis.
yFloatThe position of the avatar on the y axis.
scaleFloatThe scale of the avatar. Default is set to ‘1’.
rotationFloatSet the value between 0 and 1 to rotate the avatar.
currentEmotionStringThe emotion avatar is currently showing. Changing this value to make the avatar express emotion. Emotions the avatar can express is stored at availableEmotion.
availableEmotionString[]An array of string containing all available emotion the avatar can express. Pass one of those string to currentEmotion will change the emotion.
audioSourceStringThe source of the audio, usually an Url. The audio will be played automatically once the value is changed.
rawBase64AudioStringThe source of the audio which is encoded with Base64 format. Usually used with base64EncodedString() to encode the audio data.